Can't get to the DOM element - javascript

I got voting script on my page (jQuery Raty), everything work's fine but I want to change rate number in my ajax after voting.
Have problem with getting to span class .glosy
My html:
<div class=\"movie__rate\">
<div class=\"score\" data-score=\"$czy_glosowal2[ocena]\" data-user=\"$stat[id]\" data-movie=\"$podobny_film[id]\"></div>
<span class=\"movie__rate-number\">
<span class=\"glosy\">170</span>
głosów</span>
</div>
My JS:
('.score').raty({
click: function(score) {
var licznik_komentarzy = $(this).find('.glosy').text();
var zapisanie_licznika = $(this).find('.glosy').val(licznik_komentarzy);
var dodanie_licznika = +$(this).find('.glosy').val() + 1;
$(this).find('.glosy').text(dodanie_licznika);
}
});
tried different methods (next(), nextAll(), find()) and still cant figure it out.

Assuming that this is actually the element (depends on how plugin is written) ... you are looking in the wrong direction in the DOM tree.
closest() looks up the tree for ancestors.
You would need to use find() to look for a descendant of .score

Related

Changing a label using JavaScript click event handler

I am trying to remove a 'Pending' label and want to add a new 'Done' label.
Please find below the code I have written so far. This code works but the Pending label is now along side the Done label. I thought the former can be removed.
$(document).on('click','.pending', function() {
var li_node = $(this).parent();
li_node.append('<span class="label success">Done!</span>');
li_node.remove('<span class="label pending">Pending</span>');
li_node.addClass('completed');
});
Screenshots of my work. Can I get rid of the Pending label and leave only the Done label?
This is the html code: I am following an online tutorial that seems to have been designed for you to have a seasoned JS coach with you;
<div id="container">
<h1>Wish List</h1>
<ol id="items">
<!-- Items will be added here -->
</ol>
<span class="total"></span>
<br/>
<input type="text" id="item"/>
<button id="add-to-list">Add to list</button>
</div>
Something tells me I should be starting a new topic for the addition to this question but that would mean duplicating all the previous code...let me know if I am breaking the rules please.
I don't have an idea how to write a jQuery selector that selects all the pending labels, using the .length property, in the JavaScript console. I am using all the previous codes and this is the screenshot of the list on my browser that I am working with. I need to get the number of pending labels and number of completed labels.
$(document).on('click','.pending', function() {
var li_node = $(this).parent();
li_node.append('<span class="label success">Done!</span>');
li_node.children(".label.pending").remove();
li_node.addClass('completed');
});
Instead of adding and removing things, just change the class and text of the label in place:
$(document).on('click','.pending', function() {
var li_node = $(this).parent();
li_node.children('.label.pending').removeClass("pending").addClass("success").text("Done!");
li_node.addClass('completed');
});
Here is a working solution, I use a $ before the variable
name when it is a jQuery object. If you remove the item after
you get the selector for its parent element. then call remove on $(this) it works.
$(document).on('click', '.pending', function () {
var $li_node = $(this).closest('li');
$(this).remove();
$li_node.append('<span class="label success">Done!</span>').addClass('completed');
});

jQuery selector is overlooking elements from a separate context

I'm making an ajax request to a page on my site with this element as a direct child of the body tag:
<div class="container" id="wantme"><div class="content"></div></div>
There's only one .container, and I want to grab its ID which I don't know.
As far as I can tell, this code should do what I want:
$.get('/page', function(data) {
id = $('.container', data).attr('id');
});
But the .container selector fails to find anything.
I did find these two workarounds. I can find .content, and I can climb up the tree like this:
id = $('.content', data).parent().attr('id');
But I can't leap directly there.
I found this workaround elsewhere on StackOverflow that works:
html = $('<div></div>').html(data);
id = html.find('.container').attr('id');
But why is it that the seemingly obvious answer doesn't work?
UPDATED ANSWER: I'll leave my original answer at the bottom, however I'm concerned it may misbehave depending on browser. jQuery's .html() makes use of Javascript's innerHTML - some browsers choose to strip <head> and <body> tags when using innerHTML, whereas others do not.
The safest method to achieve what you're after may still be the workaround you mentioned, like so:
var data = '<!doctype html><html><body><div class="container" id="findme"><div class="content"></div></div></body></html>';
var $container = $("<div />").html(data).find(".container");
var id = $container.attr("id");
console.log(id);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
More information as to the browser-related issues can be found here.
PREVIOUS ANSWER:
When you pass HTML to a jQuery element, it will ignore the <body> tags, as well as anything outside of them. Given the data string in your JSFiddle, $(data) will create something that looks like this:
<div class="container" id="findme">
<div class="content"></div>
</div>
As you can see in the HTML above, your .container isn't inside of $(data) - it is $(data).
Because $(data) is representing your .container element, you should just be able to do $(data).attr("id") to retrieve what you're after.
var data = '<!doctype html><html><body><div class="container" id="findme"><div class="content"></div></div></body></html>';
var id = $(data).attr('id');
console.log(id);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You are not getting the ID from $('.container', data).attr('id'); is because you are setting the value of the second parameter. What you want to do is this: $('.container ' + data).attr('id');.
Update:
If data is a string then you should convert it into a DOM element: $('.container', $(data)).attr('id');

Copy divs with certain id's to targets with related id's

How do I copy the content from all divs with a certain class or a certain beginning of an id to a bunch of divs with related id's? The examples I found didn't go through multiple copies. I have a solution that is working ok but instead of calling each copy with the id I would like to make the logic better.
Here's what I have now.
HTML (handlebars template)
<!-- the id comes from handlebar content. There are many like this -->
<pre><code id="target-example-01" class='language-markup'></code></pre>
<!-- this content is put to place once handlebars has rendered the page -->
<div id="code-examples" style="display: none;">
<div class='code-example' id="source-example-01">
this is my a code example... there are many like me...
</div>
</div>
Javascript
var source = document.getElementById('source-example-01').innerHTML;
var target = document.getElementById('target-example-01');
if (target) target.innerHTML=source;
This works ok but I have 100 examples so I wouldn't like to have 300 lines of code to manually maintain just to copy the content. How do I go through all the divs with "code-example" class and copy their content to divs with a matching id. All the source divs will have the id="source-(example-identifier)" and all the target divs will have the id="target-(example-identifier)". I guess the class wouldn't be needed if the code would go through all items with the id beginning with "source-"
I would be old school and stick with using getElementsByClassName() but since the question is how to target divs will have the id="target-(example-identifier) you can use querySelectorAll()
document.querySelectorAll('div[id^="source-example-"]')
for more information about querySelectorAll()
Returns a list of the elements within the document (using depth-first pre-order traversal of the document's nodes) that match the specified group of selectors. The object returned is a NodeList.
So the output is very much like using getElementsByClassName()
If you have any questions please leave a comment below and I will reply as soon as possible.
How to target a specific tag with a class and id?
document.querySelectorAll('div.code-example[id^="source-example-"]')
You will still need to loop through the contend just like you would for returning elements by class name but this query selector will only return div elements with the class name code-example and contains source-example- in the id attribute.
function QuerySelector() {
var Selector=document.querySelectorAll('div.code-example[id^="source-example-"]');
for(var i=0; i<Selector.length; i++){
alert(Selector[i].innerHTML);
}
}
<div class="code-example" id="source-example-01">Content Line One. - with class and id </div>
<div class="code-example">Content Line Two. - with correct class but no ID</div>
<div class="code-example" id="source-example-02">Content Line Three. - with class and id </div>
<button onclick="QuerySelector()">Get</button>
I hope this helps. Happy coding!
How do I go through all the divs with "code-example" class and copy
their content to divs with a matching id
Assuming that index of code-example elements is same as that of targets, then try
var allCodeExamples = document.getElementsByClassName( "code-example" );
for ( var counter = 0; counter < allCodeExamples.length ; counter++ )
{
var index = ("0" + counter).slice( -2 );
var target = document.getElementById( "target-example-" + index );
target.innerHTML = allCodeExamples[counter].innerHTML;
}
You can make use of data attributes for this using jquery:
<!-- the id comes from handlebar content. There are many like this -->
<pre><code id="target-example-01" class='language-markup'></code></pre>
<!-- this content is put to place once handlebars has rendered the page -->
<div id="code-examples" style="display: none;">
<div class='code-example' id="source-example-01" data-target="#target-example-01">
this is my a code example... there are many like me...
</div>
</div>
$(function(){
var targetId;
$(".code-example").each(function(){
targetId = $(this).attr("data-target");
$(targetId).html($(this).html());
});
});
I realised it makes more sense to check which examples are on the page and fetch the content for their source id's. I added another class to the code-tags "target-example"
Here's the javascript (jquery would probably make it nicer looking)
var examples = document.getElementsByClassName('target-example');
var i;
var id;
for (i = 0; i < examples.length; i++) {
id = examples[i].id;
var source = document.getElementById('source-'+id).innerHTML;
if (source) examples[i].innerHTML=source;
}

How to change the source of a child element with JavaScript?

I'm looking to change the source attribute of an image element when my parent element is clicked. The child/image element is actually nested within two div's which complicates things slightly and I have a suspicion this is where i'm going wrong in my code.
The JavaScript is as follows:
<script src="js/jquery-1.7.2.min.js"></script>
<script>
$(document).ready(function () {
$('.slideContent').hide();
$('.slideHeader').toggle(
function () {
$(this).next('.slideContent').slideDown();
$(this).children('.dropDownIcon').children('img').src = "./images/dropDownIconUp.png";
},
function () {
$(this).next('.slideContent').fadeOut();
$(this).children('.dropDownIcon').children('img').src = "./images/dropDownIconDown.png";
}
); // end toggle
}); // end ready
And the HTML is:
<div class="slideHeader">
<div class="dropDownIcon">
<img class="dropDownClass" src="./images/dropDownIconDown.png"/>
</div>
<div>
<p>2014</p>
</div>
</div>
<div class="slideContent">
<div>
<p>2014</p>
</div>
</div>
The slideDown and fadeOut functions from jQuery work fine. However the image change does not happen. So i'm confident my eror is within the following code:
$(this).children('.dropDownIcon').children('img').src = "./images/dropDownIconUp.png";
But as far as I can see, I select the correct elements in my chain. If anyone can shine any light on this it would be much appreciated. As everything else on the internet verifys the code above should work (Whilst a be little messy).
Thanks in advance.
src is an attribute of the img tag, so use .attr()
Try,
$(this).children('.dropDownIcon').children('img').attr('src', "./images/dropDownIconUp.png");
instead of using children selector twice use $(this).find('img').attr('src','./images/dropDownIconUp.png')
I know you have accepted the answer but let me tell you some points in brief
.src = "blah" would not work for jquery objects.$() always returns a jquery object and you must use .attr() or .prop() to work with jquery objects
However jquery provides a simple way to convert to javascript object
if you still want to use as a javascript object you could it this way
$(".slideHeader").children('.dropDownIcon').children('img')[0].src = "./images/dropDownIconDown.png";

Another jquery dynamic selector

I just asked a question here about selecting all id's of the form id_* where * is any string and id is the id of the element. I got a great working solution:
$("*[id^=" + id + "_]").each(function() {... // id is the element name
I need to take this one step further now:
All of my ids will be of the form: a_b_c ... where a b and c are arbitrarity strings (that do NOT contain a ''). So, now rather than selecting all the elems of the form id_* where * could be a_b_c ... I need only to select 1 level deep: i.e. all elems of the form id_a. So in other words it stops at the next ''. Is this possible?
As an example:
If my id is: first
And there exist id's: first_second, first_second_third
It will select only first_second
Sounds like you are storing too many values in the id of the field. With HTML5 we now have data- attributes.
Perhaps, you should be making use of data- attributes something like this to link them?
<div id="a">
</div>
<div id="b0" data-parentId='a'>
</div>
<div id="b1" data-parentId='a'>
</div>
<div id="b2" data-parentId='a'>
</div>
<div id="c" data-parentId='b1'>
</div>
It will still validate, as any non-standard attribute starting with data- will be considered valid.
See: http://ejohn.org/blog/html-5-data-attributes/
Your jQuery selectors can then make use of this new attribute, rather than trying to parse strings
Something like this would select all of a's children
var childrenOfA = $("div[data-parentId='a']);
What I ended up doing (and I'm open to faster implementations) is:
$("*[id^=" + id + "_]").each(function() {
//here I simply split the id and test the size of the array
//if its too large (i.e. too deep in the tree), I return true (to continue
// to the next iteration):
var row = $(this);
var split = row.attr('id').split("_");
if(split.length > SOME_PREDETERMINED_VAL)
return true;
//code here
});
I am not totally happy with this since it still traverses all elements (or would it do this anyway regardless of the filter in the each() function??).
This doesn't give you the whole solution, but you could try the attribute prefix selector or the attribute starts with selector
That will allow you to select any descendant of an element:
$("[id^='a_b_']").each(....
Will think how to remove the grandchildren etc, but this might get you started.
EDIT
I have just found that a similar question was asked about jQuery wildcards - this looks as if it will do what you need.
It seems like you are seriously overcomplicating this task. Let's say your structure is currently like this:
<div id="a">
<div id="a_b">
<div id="a_b_c">
</div>
</div>
</div>
Why don't you just do something along these lines...
<div id="a">
<div class="b">
<div class="c">
</div>
</div>
</div>
So, if I JUST wanted #a .b I would do:
$("#a .b").not("#a .c").show();
Makes it a bit more semantic and readable as well. Am I understanding what you're trying to do? Might need to shed a bit more light on what exactly you're doing
The obvious solution is changing your document, for example instead of
<div id="a"></div>
<div id="a_b"></div>
<div id="a_b_c"></div>
you could write
<div id="a" class="l1"></div>
<div id="a_b" class="l2"></div>
<div id="a_b_c" class="l3"></div>
and then select $('.l2[id^=a_]'). If that is not an option, you could try some sort of sieve scheme:
var set = $('[id^='+id+'_]'), i = 0;
while (i < set.length) {
var e = set.eq(i);
if (e.attr('id').substr(id.length+1).match('_')) {
set = set.not(e);
} else {
i++;
}
set = set.not($('[id^='+e.attr('id')+'_]'));
}
(I haven't tested, so there might be errors, and I'm not sure not is the one that subtracts from a result set, but you get the idea.)
It depends on the document structure and browser whether this will be actually faster than the naive implmentation of simply walking through the while set and skipping everything with two _ in the id. (High number of branches per node helps, and it will be probably faster on browsers which have a native implementation of the CSS3 prefix selector which jQuery can call on.)
update: fixed some mistakes. The logic might change depending on your structure, e.g. the innermost if branch is unnecessery if foo_bar always precedes foo_bar_baz.

Categories

Resources