0

I'd like to hide an element that is inserted/injected to my Shopify store with an external app. It appears about a second later after everything has finished loading on the site and has a class called "hidethis" and a bunch of other elements.

This did not work and I have no idea what else to try.

$(".hidethis").hide();

I'm trying to hide this element based on the location of the user in the following manner:

 jQuery.ajax( {
  url: '//api.ipstack.com/check?access_key=xxx&fields=country_code',
  type: 'POST',
  dataType: 'jsonp',
  success: function(location) {



    if (location.country_code === 'EE') {


  $(function() {
  // if geolocation suggest you need to hide, execute this as soon as possible
  var sheet = window.document.styleSheets[0];
  sheet.insertRule('.cart__options { display:none; }', sheet.cssRules.length);




})

  } 
 }
} );
Ron
  • 15
  • 6
  • 2
    Can we see the full markup of the added element? – Teemu Oct 14 '19 at 12:43
  • https://developer.mozilla.org/en/docs/Web/API/MutationObserver – Alex Oct 14 '19 at 12:44
  • The main element has got a class called "hidethis". I think the other elements are not relevant. Maybe there is a way to make a function that checks for changes or constantly keeps scanning the page for new elements. I was able to hide the element when I edited the CSS from the developer view. Not sure why I'm getting downvoted. – Ron Oct 14 '19 at 12:50
  • Your copying of my example took too much of my test code. you just want `success: function(location) { if (location.country_code === 'EE') { var sheet = window.document.styleSheets[0]; sheet.insertRule('.hidethis { display:none; }', sheet.cssRules.length); } }` – mplungjan Oct 14 '19 at 14:13
  • You can also reverse it and show it if it is NOT EE – mplungjan Oct 14 '19 at 14:27

4 Answers4

0

Best solution: CSS

.hidethis { display:none }

If this is not possible and you need JS

  var sheet = window.document.styleSheets[0];
  sheet.insertRule('.hidethis { display:none; }', sheet.cssRules.length);

$(function() {
  // if geolocation suggest you need to hide, execute this as soon as possible
  var sheet = window.document.styleSheets[0];
  sheet.insertRule('.hidethis { display:none; }', sheet.cssRules.length);


  // test code - remove this when you insert the above code in your page
  setTimeout(function() {$("#container").append('<div class="hidethis">Hide this</div>');}, 1000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container"></div>

which translates to your Ajax example:

$.ajax({
  url: '//api.ipstack.com/check?access_key=xxx&fields=country_code',
  type: 'POST',
  dataType: 'jsonp',
  success: function(location) {
    if (location.country_code === 'EE') {
      var sheet = window.document.styleSheets[0];
      sheet.insertRule('.hidethis { display:none; }', sheet.cssRules.length);
    }
  }
})

Alternatively add a

<style>.hidethis { display:none }</style> 

to the page before where the content you want to hide is going to appear. Then in your ajax do

if (location.country_code != 'EE') { $(".hidethis").show() }

You can also try an interval

$(function() {
  var tId = setInterval(function() {
    var $hide = $(".hidethis");
    if ($hide.length>0) {
      clearInterval(tId);
      $hide.hide();
    }      
  },500);


  // test code - remove this when you insert the script in your page
  setTimeout(function() { $("#container").append('<div class="hidethis">Hide this</div>'); },1000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="container"></div>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • The second code worked but the element appears briefly. It's a solution but not the ideal desired result – Ron Oct 14 '19 at 13:11
  • I don't want to hide it for everyone. I'm checking the geolocation and trying to hide it based on the location of the user. – Ron Oct 14 '19 at 13:16
  • I seem to get this error - "Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules". I probably messed it up trying to insert it into my code. – Ron Oct 14 '19 at 13:39
  • You likely need a stylesheet in the top of the page. I did not test if there was one – mplungjan Oct 14 '19 at 13:40
  • Please update the question. I cannot read the code in an unformatted comment – mplungjan Oct 14 '19 at 13:41
  • It is commented out. I added the code to my question. – Ron Oct 14 '19 at 13:43
  • $(function() {}) is a "page load" directive that does not belong in your ajax. Just add `var sheet = window.document.styleSheets[0]; sheet.insertRule('.cart__options { display:none; }', sheet.cssRules.length)` – mplungjan Oct 14 '19 at 14:08
  • It still gives the same error though and there definitely are style sheets. It's a Shopify store... Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules – Ron Oct 14 '19 at 14:53
  • Then I suggest this: Add a `` to the page before where the content you want to hide is going to appear. Then in your ajax do `if (location.country_code != 'EE') { $(".hidethis").show() }` – mplungjan Oct 14 '19 at 14:59
  • Now we're back at the original problem. The code runs before the element gets added to the page and stays hidden. – Ron Oct 14 '19 at 15:39
  • Maybe it's possible to insert the style code into the page using jquery. So when the element gets injected it will either be visible or hidden depending on what jquery did based on the geolocation? – Ron Oct 14 '19 at 15:41
  • That is what I am trying to do from the start but you say it gives error on your page `var sheet = window.document.styleSheets[0]; sheet.insertRule('.hidethis { display:none; }', sheet.cssRules.length);` – mplungjan Oct 14 '19 at 15:43
  • I didn't even realize... What if I create a new stylesheet that hides it. Can javascript call it if location.country_code == 'EE'? – Ron Oct 14 '19 at 15:45
  • Ok, that did the trick. I used $('head').append(). Thanks for the help. – Ron Oct 14 '19 at 15:54
  • Sure, same idea as adding it to an existing stylesheet – mplungjan Oct 14 '19 at 16:03
0

Here an example how to add events:
https://stackoverflow.com/a/48745137/155077

functional equivalent to jQuery .on.

Instead of adding an event-handler, you'll just have to hide it.

subscribeEvent(".feed", "click", ".feed-item", function (event) { /* here comes code of click-event*/ });

The whole thing works with MutationObserver:

// Options for the observer (which mutations to observe)
let config = { attributes: false, childList: true, subtree: true };

// Create an observer instance linked to the callback function
let observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(nodeToObserve, config);

where callback:

// Callback function to execute when mutations are observed
let callback:MutationCallback = function (
    mutationsList: MutationRecord[], 
    observer: MutationObserver)
{
    for (let mutation of mutationsList)
    {
        // console.log("mutation.type", mutation.type);
        // console.log("mutation", mutation);

        if (mutation.type == 'childList')
        {
            for (let i = 0; i < mutation.addedNodes.length; ++i)
            {
                let thisNode: Node = mutation.addedNodes[i];
                allDescendants(thisNode); // here you do something with it
            } // Next i 

        } // End if (mutation.type == 'childList') 
        // else if (mutation.type == 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.');

    } // Next mutation 

}; // End Function callback 
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
0

Your problem isn't actually about an element being added by an external app, the problem is that when your code to hide the element is executed the element isn't on the DOM yet. Because the element is being added sometime later after all your JavaScript code was already executed.

So, you have to execute your code after the element is added. One way to do that is by using MutationObserver.

Here is a simple example using as referece the example in MDN:

<div id="some-id"></div>
// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
const config = { childList: true, subtree: true };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    for(let mutation of mutationsList) {
        if (mutation.type === 'childList') {
            document.querySelector('.hide').style.display = 'none';
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Add a timeout to simulate JavaScript being executed after all your code was executed.
setTimeout(() => {
    document.getElementById('some-id').innerHTML = '<span class="hide">Hello world</span>';
}, 1000);
sidney
  • 1,241
  • 15
  • 32
  • Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'. – Ron Oct 14 '19 at 13:14
  • Are you trying to get the parent element where the .hidethis element will be? Are you using jQuery to get the element (jQuery doesn't return Node elements, you will have to do this $(selector)[0])? – sidney Oct 14 '19 at 13:34
-1

1 : at first , you inspect in your browser and find the element 2 : use $(document).ready() and hide that element