0

I am failing to target an div when this div has a certain id if the current page had

<div id="global">    

   <div id="videosContainer" data-has-video="1" data-video= "youtube">
    <iframes here> and some content
   </div>  

    <div id="content"> </div>

</div>

I need to listen to clicks on the #content area on pages where the current state/DOM of the page has inside the div with id #videosContainer a data-video= "youtube".

The difficulty is to target an area based on if another div (same level in the DOm= descendant of #global) has a certain data attribute.

 var $clickableAreaForStateWithYoutube  = $('#content #videosContainer[data-video] = "youtube"');

$clickableAreaForStateWithYoutube.on('click', function(e) {
        alert("a click was performed while a youtube video was playing")
        resetTimer("timer");
        //do stuff
});

If the value is not "youtube", i don't want the event that I define on my listener below to kick in. that's why I need to target only pages whose current state have data-attribute="youtube"

Values of the data attribite "data-video' can be:

  • "youtube"

  • "vimeo"

  • does not exist: in which case it's NOT that there is data-video="" but there is just no data-video inside the div (if needed I could change this behavior to have data-video="")

If possible, I'd rather find an actual way to target the element with jquery, that is to say find a way to define the area, and not to just add everytime (a lof of times in my codebase) do some condition (something along the line of adding inside the $clickableAreaForStateWithYoutube.on click listener a if #videosContainer has data-video equal to "youtube")

Mathieu
  • 3,841
  • 9
  • 45
  • 89
  • Actually I don't think you can target an element if an other element has certain attribute. You should instead bind the element if the other element match the condition. – Nicolas Cami Apr 13 '18 at 09:06
  • @NicolasCami Taht's what I was afraid of, maybe the only way is a if condition – Mathieu Apr 13 '18 at 09:07
  • @nicolas you can do it if the target is a descendant for example: https://stackoverflow.com/questions/42554322/select-data-attribute-from-one-div-add-class-to-another-div-which-has-same-data.But for me it's a "sibling"= a same-level div coimpared to their parent #global – Mathieu Apr 13 '18 at 09:07
  • target is the descendant or the sibling? – gurvinder372 Apr 13 '18 at 09:08
  • @gurvinder372 no check the code snippet in my question: it's the same "level". i think it can be called a sibling even – Mathieu Apr 13 '18 at 09:09
  • @Mathieu Indeed you're right, my comment has not enough precise. But targeting a neighbour is not possible I guess. – Nicolas Cami Apr 13 '18 at 09:09
  • @NicolasCami yes but I am trying to go beyond usual "limits" haha, seriously, trying to make sure it is not possible – Mathieu Apr 13 '18 at 09:10
  • It would only be possible if the element order was the other way around - adjacent or general sibling combinator could come into play then. – CBroe Apr 13 '18 at 09:11
  • what do you mean by general sibling? – Mathieu Apr 13 '18 at 09:12
  • 1
    https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_selectors – CBroe Apr 13 '18 at 09:12
  • the fatc they have the same parent does not make them what you call "general" siblings? – Mathieu Apr 13 '18 at 09:12
  • ok then let's say I can make them siblings. just edited my code to make them siblings – Mathieu Apr 13 '18 at 09:13
  • They are siblings; but the adjacent and general sibling combinator both only work in one direction - you can select an element B based on that it has a sibling A coming before it, but not the other way around. – CBroe Apr 13 '18 at 09:14
  • i can change the order no problem, in my app it works boteh ways will edit the quesiton now. – Mathieu Apr 13 '18 at 09:15
  • 1
    Basically `[data-video="youtube"] ~ #content` should already do it then. – CBroe Apr 13 '18 at 09:17
  • let me try, for me it's quite "advanced" js targeting hehe – Mathieu Apr 13 '18 at 09:18
  • Although that will not take into account any dynamic changes to the DOM - you’d have to combine it with _event delegation_ if that is an additional requirement, that it more or less “automatically” handles or ignores the click based on whether that previous sibling is currently present or not ... – CBroe Apr 13 '18 at 09:22
  • 1
    @CBroe Didn't know th sibling combinator, good catch! Just tested the `[data-video="youtube"] ~ #content` selector, it works – Nicolas Cami Apr 13 '18 at 09:22
  • @cbroe what do you mean by "Although that will not take into account any dynamic changes to the DOM - you’d have to combine it with event delegation ". Indeed based on what the usr does, if I show a vimeo video for example I'll update the data-video-hosting to "vimeo" so if a suer clicks on #content, the event I defined when user click on data-hosting=youtube should not kick in, right? – Mathieu Apr 13 '18 at 09:24
  • If you select the element using the selector I mentioned (or any other, for that matter), and then go `$(selector).on('click', ...)`, then this event handler is bound to that element, and will from now on fire whenever a click on this element occurs - whether the yt-video-element before it still exists at that point, doesn’t matter any more. _Event delegation_ is a way to handle this - you bind the handler to an element higher up the chain (here f.e. `#global`), and pass the selector along as well, so that it can then be evaluated each time a click is handled. – CBroe Apr 13 '18 at 09:30
  • sure in my use-case i use .one so that it only triggers once, and in my very specific use case this way of handling it is enough – Mathieu Apr 13 '18 at 09:31
  • @CBroe If you want to add the sibling as a proper answer o will upvote it as it is the closest to my need – Mathieu Apr 13 '18 at 09:34

2 Answers2

1

This wasn’t possible using the DOM structure presented in your question originally - reason for that is that CSS can only select “downwards” or “to the right”, but not upwards/to the left. (See also Is there a CSS parent selector? )

When you change the order however, so that the element whose (possible non-)existence is the deciding factor for selecting the other one comes before that one now, you can use the adjacent or general sibling combinator (which one depends on whether the elements follow each other immediately, or if there’s other elements in between them.

The basic way to select the #content element here based on the YT-video element coming before it using the general sibling combinator would be

[data-video="youtube"] ~ #content
CBroe
  • 82,033
  • 9
  • 81
  • 132
0

Selector is incorrect, attribute value needs to be inside [] and content is not the parent of element which has this data-attribute

  var $clickableAreaForStateWithYoutube  = $('[data-video="youtube"]');

to include vimeo as well use comma to add another selector

  var $clickableAreaForStateWithYoutube  = $('[data-video="youtube"], [data-video="vimeo"]');

Or you can make an array of such values

var values = ["youtube", "vimeo"];
var $clickableAreaForStateWithYoutube = $('[data-video]');
$clickableAreaForStateWithYoutube.on('click', function(e) {
    var dataVideo = $(this).data( "video" );
    values.includes( dataVideo ) ? alert( "value correct" ) :  alert( "value incorrect" )
});

Edit

If you want to select element with data-video on clicking #content, then

var $clickableAreaForStateWithYoutube = $('#content');
$clickableAreaForStateWithYoutube.on('click', function(e) {
    var $dataVideoEl = $(this).next("[data-video]");
    if( $dataVideoEl.length > 0 ) //to check if the element exists
    {
       var dataVideo  = $dataVideoEl.data( "video" );
       values.includes( dataVideo ) ? alert( "value correct" ) :  alert( "value incorrect" )
    } 
});
gurvinder372
  • 61,170
  • 7
  • 61
  • 75
  • had spotted it too – Mathieu Apr 13 '18 at 09:03
  • but the quesition is how to taregt the div #content on pages where the div #videoscontainer has a certain data attribute. please read the quesiton where i mention the "difficulty". – Mathieu Apr 13 '18 at 09:03