Fetch api fails to send the image to the server and returns a 404 error

I’m creating a function that sends an image to a server using JavaScript and Spring Boot.

However, when using the fetch API in JavaScript code to send an image file to the server, the server cannot be accessed and a 404 error occurs.

add-page.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Document</title>
    <script type="text/javascript" th:inline="javascript">
        function submitImage() {
        const name = document.querySelector('input[name="name"]').value;
            const image = document.querySelector('input[type="file"]').files[0];

        const formData = new FormData();

            formData.append('image', image);
            formData.append('name', name);

        fetch('/add', {
        method: 'POST',
        body: formData
        })
        .then(response => {
            console.log(response)
        })
        .catch(error => {
            console.error('Error', error);
        });


    }
    </script>
</head>
<body>
<div class="container">
    <div class="mt-5">
        <input type="file" name="image" class="form-control mt-2">
        <input name="name" class="form-control me-2" type="search" placeholder="enter" aria-label="Search">
        <button class="btn btn-outline-success" type="button" onclick="submitImage()">
            submit
        </button>
    </div>
</div>
</body>
</html>

ImageController

@Controller
public class ImageController {

    @GetMapping("/add")
    public String getAddPage() {
        return "add-page";
    }
    
    @PostMapping("/add")
    public String add(@RequestParam("image") MultipartFile image, @RequestParam("name") String name){
        System.out.println(image);
        System.out.println(name);

        return "add-page";
    }
}

If I send a String type in formData, it arrives at the controller just fine, but if I send it including a File, it does not arrive at the controller and a 404 not found error occurs.

Can anyone tell me how to send an image file in formData using the fetch function?

I tried changing Content-Type to multipart/form-data, but it didn’t work.

When I use Post Man to send the image, it arrives at the controller, but when I use the fetch function, it doesn’t enter the controller.

dragula how to configure more than 2 containers

I searched and tried for hours with no success. Now I need help.

I’m using dragula on three containers. The following code is what I’m using now. It works, but it’s not exactly what I need.

dragula([
document.getElementById('containerOne'),
document.getElementById('containerTwo'),
document.getElementById('containerThree')
],{
copy: function (el, source) {
      return source === document.getElementById('containerOne')
},
accepts: function (el, target) {
      return target !== document.getElementById("containerOne")
},
revertOnSpill: true
})

What it does:

  • Copy Element from containerOne to containerTwo
  • Copy Element from containerOne to containerThree
  • Move Element from containerTwo to containerThree
  • Move Element from containerThree to containerTwo
  • Do not allow any element into containerOne

But what I need is (please note difference on line 4)

  • Copy Element from containerOne to containerTwo
  • Copy Element from containerOne to containerThree
  • Move Element from containerTwo to containerThree
  • Copy Element from containerThree to containerTwo
  • Do not allow any element into containerOne

How do I configure the extra copy function ?
Any help greatly appreciated. Thanks !

Why mutation observer is not working for some pages once page is fully loaded – Chrome Extension

Puzzled by this problem.
I am trying to execute this simple code which just checks the changes of attributes on my specific created element. It works fine when the page is in loading state but once I reload page and wait for it to be fully loaded, then it doesn’t matter which piece of new code I try, it just doesn’t work. I also realized it works fine for many other sites but not for this specific website.

For context, this specific website is medical service provider, it uses angular probably and uses state concepts like history.pushState etc without reloading the page.

function initiateObserverListener() { 
const dataHolder = document.createElement("div"); 
dataHolder.setAttribute("id", "extension-dataHolder"); 
document.body.appendChild(dataHolder);

// Create and set up the observer
const observer = new MutationObserver(function (mutations) {
    console.log("Here");
    mutations.forEach(function (mutation) {
        console.log("Mutation executed: ", mutation.type);
        if (mutation.type === "attributes" && mutation.attributeName === "base64data") {
            console.log("in mutation");
            console.log(mutation.target.getAttribute("base64data"));
        }
    });
});

observer.observe(document.documentElement, {
    attributes: true,
    childList:true,
});

dataHolder.setAttribute("base64data", "exampleBase64Data");
initiateObserverListener();

How to show only first line?

I am having trouble with this problem for a long time now. My problem is that I cannot figure out, how to save all the data from the Input Field to localstorage yet only show the first line in the list.

const ProgButton = document.getElementById("ProgButton")
const InputFieldProg = document.getElementById("InputFieldProg")
const ItemListProg = document.getElementById("ItemListProg")


const Main = document.getElementById("main")

LoadProgTasks()

function AddProgTask() {
    const ProgTask = InputFieldProg.value
    

    if (ProgTask) {
        CreateProgTaskElement(ProgTask)

        InputFieldProg.value = ''

        SaveProgTasks()
    }

}

ProgButton.addEventListener("click", AddProgTask)

function CreateProgTaskElement(ProgTask) {

    const ProgListItem = document.createElement("li")

    const firstLine = ProgTask.split('n')[0];
    const taskContent = document.createElement('div')
    taskContent.innerHTML = firstLine.replace(/n/g, '<br>')


    const DeleteProgButton = document.createElement('button')
    DeleteProgButton.textContent = "Megtekint"
    DeleteProgButton.className = "DeleteProgBut"

    DeleteProgButton.dataset.fullText = ProgTask;

    ProgListItem.appendChild(taskContent)
    ProgListItem.appendChild(DeleteProgButton)

    DeleteProgButton.addEventListener("click", function() {
        Main.innerHTML = DeleteProgButton.dataset.fullText.replace(/n/g, '<br>');
        SaveProgTasks()
    })

    ItemListProg.appendChild(ProgListItem)
}

function SaveProgTasks() {
    let ProgTasks = []

    ItemListProg.querySelectorAll('li').forEach(function(item){
        ProgTasks.push(item.querySelector('div').innerHTML.replace('Megtekint', ''))
    })

    localStorage.setItem('ProgTask', JSON.stringify(ProgTasks))
}

function LoadProgTasks() {

    const ProgTasks = JSON.parse(localStorage.getItem('ProgTask') || '[]')

    ProgTasks.forEach(function(ProgTask) {
        CreateProgTaskElement(ProgTask)
})}

Please ignore that it is called Delete Button. it should be View Button but I havent changed it yet.
Here is the relevant HTML:

<aside id="bal"><div class="title">Prog</div>
        <ul id="ItemListProg"></ul>
        </aside>
        <div id="main">Main Content</div>
<div class="cont"><textarea id="InputFieldProg" rows="10" cols="50" placeholder="Írj ide..."></textarea>

        <button class="add" id="ProgButton">Hozzá adás</button></div>

What I want to ultimately achieve is lets say I write in the text area:
Javascript 2.

Make me a meal.

Now.

Only the Javascript 2. will be shown in the list but when I click on the button next to the list item in the main content I will see the whole thing that I wrote earlier not just the Javascript 2.

Quelqu’un peut-il m’aider à résoudre une erreur “Uncaught TypeError: Cannot read property ‘length’ of undefined” en JavaScript?

Salut tout le monde,

Je travaille sur un petit projet en JavaScript, et je suis tombé sur une erreur que je n’arrive pas à résoudre. Voici l’erreur que je reçois dans la console :

Uncaught TypeError: Cannot read property 'length' of undefined

Je pense que l’erreur se produit dans la fonction suivante :

function processArray(arr) {
    for (let i = 0; i < arr.length; i++) {
        console.log(arr[i]);
    }
}

let data;
processArray(data);

Je comprends que l’erreur indique que arr est probablement undefined au moment où j’essaie d’accéder à sa propriété length. J’ai essayé d’ajouter une vérification pour m’assurer que arr n’est pas undefined avant de passer à la boucle, mais je ne suis pas sûr de la meilleure façon de le faire.

Quelqu’un pourrait-il me montrer comment corriger ce problème ou m’expliquer ce qui cause cette erreur ?

Merci pour votre aide !

Can’t set html for onchange for input

I am creating inputs in a table via a loop.
First I create a new cell

var nestedCell = newRow.insertCell(columncounter);

Then I create a new input, each input has a unique ID.

let input = document.createElement('input');
input.type = 'text';
input.id = thisInputID;
input.value = value;

Then I try to insert an “onchange” function to that input

input.onchange =  function() { 
   alert(thisInputID);
}

The onchange function is fired, but because the value of thisInputID changes on every iteration only the last “thisInputID ” is displayed instead of the id for that particular input. This is a problem. How do I assign an onchange function to each input which will pass a unique identifier for that input?

Here is the code all in one block:

                        var nestedCell = newRow.insertCell(columncounter);

                        let input = document.createElement('input');
                        input.type = 'text';
                        input.id = thisInputID;
                        input.value = value;
                        input.onchange =  function() { 
                            alert(thisInputID);
                        }

                        nestedCell.appendChild(input);

Node.js Puppeter | I can’t pass Discord verification with 2captcha

Normally, I can pass the captcha when I try it on other sites. But there is no continue button on Discord, and that’s why Discord does not see that this has been resolved.

As you can see below, I insert the captcha answer, but the captcha is not solved.

enter image description here

My code where I’m having problems:

import { Solver } from '2captcha-ts';

const solver = new Solver(apiKey);
const apiKey = 'apikey';

await page.waitForSelector("iframe[src*='https://newassets.hcaptcha.com/captcha/']");

    const sitekey = "4c672d35-0701-42b2-88c3-78380b0db560"

    console.log(`Sitekey: ${sitekey}`);

    const res = await solver.hcaptcha({
        pageurl: "https://discord.com/login",
        sitekey: sitekey,
    });

    console.log(res);

    const captchaAnswer = res.data;

    await page.evaluate((captchaAnswer) => {
        document.querySelector("textarea[name='h-captcha-response']").style.display = "block";
        document.querySelector("textarea[name='h-captcha-response']").value = captchaAnswer;
    }, captchaAnswer);

How can I toggle tabs in Bootstrap 5?

Is it possible to toggle tabs in Bootstrap 5? I mean so that clicking an already open / active tab will deactivate / close the cantent, so that no tabs are active?

Bootstrap docs

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<ul class="nav nav-tabs" id="myTab" role="tablist">
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="home-tab" data-bs-toggle="tab" data-bs-target="#home-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Home</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Profile</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact-tab-pane" type="button" role="tab" aria-controls="contact-tab-pane" aria-selected="false">Contact</button>
  </li>
</ul>
<div class="tab-content" id="myTabContent">
  <div class="tab-pane fade" id="home-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">Home: Bacon ipsum dolor amet hamburger brisket chicken drumstick jerky flank bresaola strip steak pork belly shank. Tongue tenderloin porchetta, swine drumstick spare ribs bresaola jowl meatloaf. Drumstick doner shoulder, beef ribs venison andouille
    ball tip flank. Kielbasa beef frankfurter, venison swine ball tip picanha doner fatback corned beef ham. Tenderloin leberkas short loin, ham drumstick doner alcatra chislic burgdoggen chicken. Sausage andouille pork belly flank tongue burgdoggen pork
    capicola pork chop hamburger short loin rump pork loin shank. Cow boudin jowl, short ribs chicken chislic swine. Pancetta capicola turducken andouille. Porchetta corned beef jowl, buffalo brisket shoulder capicola tail pig shank swine hamburger frankfurter.
    Bresaola alcatra chuck fatback turkey filet mignon ham hock flank ground round spare ribs ball tip shank t-bone. Swine pork loin sirloin fatback cow pork chop short loin chicken salami. Chicken chuck shankle flank, turducken short ribs buffalo. Spare
    ribs porchetta pig burgdoggen pork loin tongue tri-tip pork chop. Turducken meatball frankfurter spare ribs tongue meatloaf, kevin bresaola pork chop short loin fatback leberkas beef ribs brisket. Kevin chuck pork pig, prosciutto picanha shankle burgdoggen
    t-bone ball tip beef. Bresaola picanha brisket porchetta tri-tip chislic doner tongue short loin filet mignon flank leberkas andouille landjaeger.</div>
  <div class="tab-pane fade" id="profile-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">Profile: Bacon ipsum dolor amet hamburger brisket chicken drumstick jerky flank bresaola strip steak pork belly shank. Tongue tenderloin porchetta, swine drumstick spare ribs bresaola jowl meatloaf. Drumstick doner shoulder, beef ribs venison andouille
    ball tip flank. Kielbasa beef frankfurter, venison swine ball tip picanha doner fatback corned beef ham. Tenderloin leberkas short loin, ham drumstick doner alcatra chislic burgdoggen chicken. Bresaola alcatra chuck fatback turkey filet mignon ham
    hock flank ground round spare ribs ball tip shank t-bone. Swine pork loin sirloin fatback cow pork chop short loin chicken salami. Chicken chuck shankle flank, turducken short ribs buffalo. Spare ribs porchetta pig burgdoggen pork loin tongue tri-tip
    pork chop. Turducken meatball frankfurter spare ribs tongue meatloaf, kevin bresaola pork chop short loin fatback leberkas beef ribs brisket. Kevin chuck pork pig, prosciutto picanha shankle burgdoggen t-bone ball tip beef. Bresaola picanha brisket
    porchetta tri-tip chislic doner tongue short loin filet mignon flank leberkas andouille landjaeger.</div>
  <div class="tab-pane fade" id="contact-tab-pane" role="tabpanel" aria-labelledby="contact-tab" tabindex="0">Contact: Bacon ipsum dolor amet hamburger brisket chicken drumstick jerky flank bresaola strip steak pork belly shank. Tongue tenderloin porchetta, swine drumstick spare ribs bresaola jowl meatloaf. Drumstick doner shoulder, beef ribs venison andouille
    ball tip flank. Kielbasa beef frankfurter, venison swine ball tip picanha doner fatback corned beef ham. Tenderloin leberkas short loin, ham drumstick doner alcatra chislic burgdoggen chicken. Sausage andouille pork belly flank tongue burgdoggen pork
    capicola pork chop hamburger short loin rump pork loin shank. Cow boudin jowl, short ribs chicken chislic swine. Pancetta capicola turducken andouille. Porchetta corned beef jowl, buffalo brisket shoulder capicola tail pig shank swine hamburger frankfurter.
    Bresaola alcatra chuck fatback turkey filet mignon ham hock flank ground round spare ribs ball tip shank t-bone. Swine pork loin sirloin fatback cow pork chop short loin chicken salami. Chicken chuck shankle flank, turducken short ribs buffalo. Spare
    ribs porchetta pig burgdoggen pork loin tongue tri-tip pork chop. Turducken meatball frankfurter spare ribs tongue meatloaf, kevin bresaola pork chop short loin fatback leberkas beef ribs brisket. Kevin chuck pork pig, prosciutto picanha shankle burgdoggen
    t-bone ball tip beef. Bresaola picanha brisket porchetta tri-tip chislic doner tongue short loin filet mignon flank leberkas andouille landjaeger.</div>
</div>

Jsfiddle

Chrome extension to change youtube video title leads to empty title on the next video when I click next

I’m working on youtube chrome extension to change the title of a Youtube video , but after changing and clicking next then, the video’s title is empty and when I click next again the custom title I wrote is appended to the new video’s title.

Here is the popup.js:

document.addEventListener('DOMContentLoaded', async () => {
    const tabId = await getCurrentTabId();

    // Load and set the auto-generate checkbox state
    chrome.storage.local.get('autoGenerateOnReload', (result) => {
        document.getElementById('autoSet').checked = result.autoGenerateOnReload || false;
    });

    // Listen for video changes
    chrome.runtime.onMessage.addListener((message) => {
        if (message.type === 'VIDEO_CHANGED') {
            handleVideoChange(tabId);
        }
    });
});

document.getElementById('changeTitle').addEventListener('click', async () => {
    const customTitle = document.getElementById('customTitle').value;
    if (customTitle) {
        const tabId = await getCurrentTabId();
        setTitleOnPage(tabId, customTitle);
        chrome.storage.local.set({ storedTitle: customTitle });
    }
});

document.getElementById('autoSet').addEventListener('change', (event) => {
    chrome.storage.local.set({ autoGenerateOnReload: event.target.checked });
});

document.getElementById('generateAIButton').addEventListener('click', async () => {
    const tabId = await getCurrentTabId();
    generateNewTitle(tabId);
});

async function handleVideoChange(tabId) {
    // Clear stored title on video change
    chrome.storage.local.remove('storedTitle');

    chrome.storage.local.get('autoGenerateOnReload', async (result) => {
        if (result.autoGenerateOnReload) {
            await generateNewTitle(tabId);
        } else {
            const originalTitle = await getOriginalTitle(tabId);
            setTitleOnPage(tabId, originalTitle);
        }
    });
}

async function setTitleOnPage(tabId, title) {
    await chrome.scripting.executeScript({
        target: { tabId },
        func: (newTitle) => {
            const titleElement = document.querySelector('h1.style-scope.ytd-watch-metadata yt-formatted-string');
            if (titleElement) {
                titleElement.textContent = newTitle;
            }
        },
        args: [title]
    });
}

async function generateNewTitle(tabId) {
    const prompt = 'Generate a catchy YouTube title in French';
    const generateButton = document.getElementById('generateAIButton');
    generateButton.textContent = 'Loading...';
    generateButton.disabled = true;

    try {
        const newTitle = await generateUsingAI(prompt);
        if (newTitle && newTitle.trim()) {
            await setTitleOnPage(tabId, newTitle.trim());
            chrome.storage.local.set({ storedTitle: newTitle.trim() });
        } else {
            alert("Failed to generate a valid title. Please try again.");
        }
    } catch (error) {
        console.error("Error generating title using AI:", error);
    } finally {
        generateButton.textContent = 'Generate Using AI';
        generateButton.disabled = false;
    }
}

async function generateUsingAI(prompt) {
    try {
        const response = await fetch('http://localhost:3000/openai/generate-title?prompt=' + encodeURIComponent(prompt));
        const newTitle = await response.text();
        return newTitle.replace(/^"|"$/g, '');
    } catch (error) {
        console.error("Error generating title using AI:", error);
        return '';
    }
}

function getCurrentTabId() {
    return new Promise((resolve) => {
        chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
            resolve(tabs[0].id);
        });
    });
}

async function getOriginalTitle(tabId) {
    return new Promise((resolve) => {
        chrome.scripting.executeScript({
            target: { tabId },
            func: () => {
                const titleElement = document.querySelector('h1.style-scope.ytd-watch-metadata yt-formatted-string');
                return titleElement ? titleElement.textContent : '';
            }
        }, (results) => {
            resolve(results[0].result || '');
        });
    });
}

and content.js:

// content.js

// Track the last known video ID
let lastVideoId = '';

const observer = new MutationObserver(() => {
    const currentUrl = location.href;
    const videoId = new URL(currentUrl).searchParams.get('v');

    if (videoId && videoId !== lastVideoId) {
        lastVideoId = videoId;
        chrome.runtime.sendMessage({ type: 'VIDEO_CHANGED', videoId });
    }
});

// Observe changes in the DOM
observer.observe(document, { childList: true, subtree: true });

Can anyone help me to know where I’m doing anything wrong?

I have tried many approaches including using a background.js , but nothing seems to work perfectly.

Preventing Automatic Extension of Selection Range to Adjacent Divs

I have a number of consecutive DOM divs that contain text.
I created the following function to get the selected divs

When I select multiple consecutive divs by triple clicking their text in the browser, the function returns the selected divs as well as the next one that I haven’t selected.

Probably this is due to the browser’s behavior, but is there a workaround?

function get_selected_sentences_range() {
  var selection = window.getSelection();
  var sentences_obj;
  var sentences_order_range = [];
  if (selection.rangeCount > 0) {
    var range = selection.getRangeAt(0);
    var selectedNode = range.startContainer;
    while (selectedNode && selectedNode.nodeType !== Node.ELEMENT_NODE) {
      selectedNode = selectedNode.parentNode;
    }
    //if the cursor is at one of the .sentences_container children
    if ($(selectedNode).parents(".sentences_container").length > 0) {
      sentences_obj = $(".sentences_container").find(".sentence_div").filter(function() {
        //check if the selection contains this element
        if (selection.containsNode(this, true)) {
          //but if the selected text is only an end-of-paragraph character, don't include it
          if (selection.toString().trim() == "") {
            return false;
          } else {
            return true;
          }
        }
      });
    } else {
      return false;
    }
  } else {
    return false;
  }
  sentences_obj.each(function(n) {
    var this_sentence_order = $(this).attr("data-sentence-order");
    if (n == 0) { //the first selected element
      sentences_order_range.push(this_sentence_order);
    }
    //if it's the last element
    if (n == sentences_obj.length - 1) {
      sentences_order_range.push(this_sentence_order);
    }
  });
  return sentences_order_range;
}
<div>Text 1</div><div>Text 2</div><div>Text 3</div>

Update objects in array held in Dynamo DB

I am creating a placeholder entry in my DynamoDB with a format such as

id: string
created_at: string
results: array

My plan was to add to the results array of data as and when I get said result objects.

Initially, the placeholder entry had the results being just an empty array [] and I was using list_append(RESULTS, :results) to do this, which worked great.

However I have now changed the structure of the results array being stored, and the placeholder will now contain a bit of extra detail per object stored; so my results placeholder will look something like:

results: [
  {
    id: 'result-1',
    otherInfo: 'some other info',
    results: []
  }
]

and I will now aim to put the result objects received into the results array of each object in which I can match the id of the placeholder to the result data received.

How would one go about most effectively adding to these object arrays?
Would I have to pull the results, iterate through and then persist the full set of results back? Or is there a way in which I can do a simple update like I was previously with list_append?

Anonymous Functions Vs Classic Function [duplicate]

I’m not able to figure out the reason for this behavior, can any one help me understand

  let counter= (function (){
    let count = 0;
    return function() {
        count+=1;
        return count;
    }
})()

for (let i = 0; i< 3; i++){
    console.log(counter());
}

This prints an output of

 1
 2
 3

Where as the below code

 function increment() {
    let count = 0;
    return function() {
        count+=1;
        return count;
    }
}

for (let i = 0; i< 3; i++){
    console.log(increment()());
}

Prints 1 1 1 1

Can i use the old and new values from the watcher in the mounted cycle?

I need to use this.prev and this.curr in the mounted cycle, with the updated changes from the watcher. How can I access these up to date values in the mounted cycle?

 <template>
  <component
    :is="'nuxt-link'"
    :to="{ path: slug, query: { scroll: 'false' } }"
    :class="linkClasses"
    v-on:click.native="getSelectedFacet($event.target.textContent)"
  >
    <slot></slot>
  </component>
</template>

<script>
export default {
  inject: ["filterVariantState"],

  props: {
    facetKey: {
      type: String,
      required: true,
    },

    facet: {
      type: String | undefined,
      required: true,
    },

    selectedFacets: {
      type: Object,
      required: true,
    },

    selectedFacet: {
      type: String,
      required: false,
    },

    results: {
      type: Array,
      default() {
        return [];
      },
    },
  },

  data() {
    return {
      trackFacets: [],
      showAnimation: false,
      updatedFacet: null,
      updatedFacetKey: null,
      prev: {
        attributes: [],
        name: "",
      },
      curr: {
        attributes: [],
        name: "",
      },
    };
  },

  computed: {
    // Get data object from store
    dataObj() {
      return this.$store.getters["page/data"];
    },

    // Get Previous and Current Facets from store
    storedFacets() {
      return this.$store.getters["page/facets"];
    },

    // Get Selected Facets
    storedSelectedFacet() {
      return this.$store.getters["page/selectedFacet"];
    },

    facets() {
      let currentFacet = {};
      currentFacet[this.facetKey] = this.facet;

      return Object.assign({}, this.selectedFacets, currentFacet);
    },

    // Check if product is availble
    productIsAvailable() {
      return this.productAvailability ? true : false;
    },

    // Computes the slug of each facet
    slug() {
      let result;

      if (!this.filterVariantState.clearAll && this.results.length > 2) {
        result = this.results.find((x) => {
          return Object.keys(this.facets).every((facet) => {
            return (x[facet] ? x[facet].raw : null) === this.facets[facet];
          });
        });
      }

      let productSlug = result ? result.slug.raw : "";

      if (productSlug === "") {
        result = this.results.find(
          (x) =>
            x[this.facetKey] &&
            x[this.facetKey].raw === this.facets[this.facetKey]
        );
      }

      return result ? result.slug.raw : "";
    },

    // Computes product availability
    productAvailability() {
      let result =
        !this.filterVariantState.clearAll && this.results.length > 2
          ? this.results.find((x) => {
              return Object.keys(this.facets).every((facet) => {
                return (x[facet] ? x[facet].raw : null) === this.facets[facet];
              });
            })
          : this.results.find(
              (x) =>
                x[this.facetKey] &&
                x[this.facetKey].raw === this.facets[this.facetKey]
            );

 
      return result ? result.slug.raw : "";
    },

    // Current selected variant
    currentVariant() {
      return this.selectedFacet === this.facet;
    },

    // Link Classes
    linkClasses() {
      return {
        "bg-gray-100 text-gray-400": !this.productIsAvailable,
        "text-gray-900": this.productIsAvailable,
        pulse: this.showAnimation && this.currentVariant,
      };
    },

    animationIsTrue() {
      return showAnimation ? true : false;
    },
  },

  methods: {
    // Get facetKey from value // Adjust styling for styling detector for storage as it entered into the backend off
    getKeyByValue(object, value) {
      return Object.keys(object).find((key) =>
        key === "storage"
          ? object[key].replaceAll(" ", "") === value
          : object[key] === value
      );
    },

    // This method gets you the facetKey that is NOT changed when you click on a faded option and your selection has been changed
    getUnchangedKey() {
      // Get two arrays of facetKeys
      let result = this.storedFacets.map((value) =>
        value.attributes.map((attribute) =>
          this.getKeyByValue(this.dataObj.attributes, attribute)
        )
      );

      // Need the last two results to continue
      if (result.length === 2) {
        // Remove sim and network from the arrays
        result[0] = result[0].filter(
          (str) => str !== "sim" && str !== "network"
        );
        result[1] = result[1].filter(
          (str) => str !== "sim" && str !== "network"
        );

        let unchangedKey = [];

        // Compare the two arrays, if there is a matching facetKey, it means it has not changed and so we will not fire the text for that facetKey
        for (let i = 0; i < result[0].length; i++) {
          for (let j = 0; j < result[1].length; j++) {
            if (result[0][i] === result[1][j]) {
              unchangedKey.push(result[0][i]);
            }
          }
        }

        return unchangedKey ? unchangedKey : "";
      }
    },

    // Get selected facet value on click
    getSelectedFacet(value) {
      // Set the value found in the $event click
      this.updatedFacet = value.trim().toLowerCase();

      // Dispatch the getSelectedFacets action and pass through the facet value that has just been selected/clicked
      this.$store.dispatch("page/getSelectedFacet", this.updatedFacet);
    },
  },

  watch: {
    dataObj(newVal, oldVal) {
      // this.fetchFacets();
      this.prev = {
        attributes: Object.values(oldVal.attributes),
        name: this.dataObj.name,
      };
      this.curr = {
        attributes: Object.values(newVal.attributes),
        name: this.dataObj.name,
      };
    },
  },

  mounted() {
    // Conditionally show pulse animation
    let n = 1;
    let queue = [];
    // let namesQueue = [];

    // Loop through both arrays and join them create one array
    for (let i = 1; i <= n; i++) {
      let prevFacets = this.prev.attributes;
      let currFacets = this.curr.attributes;

      // let prevProductName = this.prev.name;
      // let currProductName = this.curr.name;

      console.log("prev", this.prev.attributes);
      console.log("curr", this.curr.attributes);

      // namesQueue.push(prevProductName, currProductName);

      // Loop through prev facets
      for (let j = 0; j < prevFacets.length; j++) {
        queue.push(prevFacets[j]);
      }

      // Loop through current facets
      for (let k = 0; k < currFacets.length; k++) {
        queue.push(currFacets[k]);
      }
    }

    // Loop through joint array and check for no duplicates
    for (let i = 0; i < queue.length; i++) {
      for (let j = i + 1; j < queue.length; j++) {
        if (queue[i] === queue[j]) {
          queue.splice(i, 1); // Remove the element at index i
          queue.splice(j - 1, 1); // Remove the element at index j (adjusted after removing i)
          i--; // Adjust i since the array has been modified
          break; // Restart checking from the new i position
        }
      }
    }

    // The queue removes any duplicates
    // So, if there is only pair of facets left (length === 2), then turn off the animation as only the selected facet has changed
    if (queue.length === 2) {
      this.showAnimation = false;

      // Else if, they are multiple pairs of changes and the product is still the same, then turn on the animation as the facet options have changed, and also, alert the changing text
    } else if (queue.length > 2) {
      this.showAnimation = true;

      // Conditionally show updated label

      // Find key based on the value of the selected facet found in storedSelectedFacets
      this.updatedFacetKey = this.getKeyByValue(
        this.dataObj.attributes,
        this.storedSelectedFacet
      );

      // Pass the facet key to ProductVariantFilter to trigger the "update" label
      this.$emit("updatedFacetOptions", {
        facetKey: this.updatedFacetKey,
        // Get unchanged facetKey, if there is one
        unchangedFacetKey: this.getUnchangedKey(),
      });
    }
  },
};
</script>



I tried putting my mounted content in the watcher, but i only see my animation for a second because it has to be handled in the mounted cycle

React Native Android tablet Landscape not working with expo screen orientation

I’m working in a aplication that will be only used in tablets, and i can’t configure correctly the landscape and portrait rotation, allways show portrait in my android tablet.

This is the code in my App.js:

 
const [orientation, setOrientation] = useState(
    ScreenOrientation.Orientation.PORTRAIT_UP
  );
  useEffect(() => {
    ScreenOrientation.getOrientationAsync().then((info) => {
      console.log(info);
      setOrientation(info.orientation);
    });
    
    const subscription = ScreenOrientation.addOrientationChangeListener((evt) => {
      setOrientation(evt.orientationInfo.orientation);
    });
  
    return () => {
      ScreenOrientation.removeOrientationChangeListener(subscription);
    };
  }, []);

When i rotate my tablet, this is what logs say (allways the same in landscape and portrait):

LOG {"orientationInfo": {"orientation": 1}, "orientationLock": 3} LOG {"orientationInfo": {"orientation": 1}, "orientationLock": 3} LOG {"orientationInfo": {"orientation": 1}, "orientationLock": 3} LOG {"orientationInfo": {"orientation": 1}, "orientationLock": 3}

Did you know what happends?

I’ve tried different codes, and allways i have the same result