Access daughter DIV from other daughter without ID - javascript

I have a structure as below:
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Tiger128 (v2)</h3>
</div>
<div class="panel-body">
<input class="form-control" id="tiger128v2" placeholder="String to Hash" type="text">
</div>
<div class="panel-footer">
<a class="btn btn-primary generate-hash" data-hash="tiger128v2">Generate Hash</a>
</div>
</div>
When a user presses the <a> it runs a jQuery function (using $('.generate-hash') selector) which makes a $.getJSON request passing data-hashtype. When it returns the JSON object I need it to append some text to <div class="panel-body"> however as you can see none of them have ID's.
What I have tried is something along the lines of:
$(this).parent().prev('.panel-body').append('Appending some text');
$(this).parent().parent().siblings(".panel-body").append('test');
But I cannot get it to work. Any suggestions?
$('.generate-hash').click(function (e) {
e.preventDefault();
var hashtype = $(this).data('hash');
var string = $(this).closest('.panel').find('input').val();
console.log('Started hash request for ' + hashtype + ' with a value of ' + string);
$.getJSON('ajax/hash.php', {
hashtype: hashtype,
string: string
})
.success(function(data) {
console.log('success function');
if(data.type == 'success'){
// Here is where i need to select the parents
$(this).parent().parent().siblings(".panel-body").append('test');
$(this).parent().prev('.body').append('<div class="alert alert-info"><strong>Generated Hash:</strong> <code>' + data.hash + '</code></div>');
console.log('success msg found');
}else{
$(this).parent().prev('.body').append('<div class="alert alert-' + data.type + '">' + data.msg + '</div>');
console.log('error msg found');
}
})
.fail(function() {
$(this).parent().prev('.body').append('<div class="alert alert-error"><strong>Error:</strong> We could not generate the hash for some reason. The details are below:</div>');
console.log('unable to find hash.php or other error');
});
});

You can use .prev() method:
$(this).parent().prev('.body').append('Something');
Or .closest() method:
$(this).closest('.box').find('.body').append('Something');
Edit:
You should cache the this object, within the context of the Deferred object's handlers this doesn't refer to the clicked element, also replace .success() with .done():
$('.generate-hash').click(function (e) {
// ...
var $this = $(this);
$.getJSON('ajax/hash.php', {
hashtype: hashtype,
string: string
})
.done(function(data) {
console.log('success function');
if(data.type == 'success'){
// Here is where i need to select the parents
$this.parent().parent().siblings(".panel-body").append('test');
// ...
})
.fail(function() {
$this.parent()...
});
});

use closest
closest() selects the first element that matches the selector, up from the DOM tree while parent() selects all the elements that are parent of another element in the DOM tree.
$(this).closest('.box').find('.body').append('Something');
reference closest

try something like this, try prev()
$(this).parent().prev().append('Something');

maybe pure javascript might work
var box = this.parentNode.parentNode,
body = box.getElementsByClassName('body')[0];
body.innerHTML += 'Something';

Try this,
$(this).parents('.box').find('.body').append('Something');
or
$(this).closest('.box').find('.body').append('Something');
Read parents() and closest()

Related

Dynamic jQuery unslider populated from Ajax not clearing children in <ul>

I have this unslider which display tweets polled from some sources via Ajax which refreshes every 8 sec. The Unslider works fine for the first time but subsequently when new ajax queries are fired, it is supposed to clear the first tags and repopulate with new one. For some reason, it doesn't clear out the old tags and instead appends the new tags to the old.
Here are the screenshots:
var flag = false;
(function setTweets() {
$.ajax({
type: "GET",
url: "../tweets/get_latest_tweets",
success: function(data) {
//clear all children first
$('#tweets-list').children().remove();
for (var i = 0; i < data.length; i++) {
$('<li>' + data[i].text + '<div class="card-footer bg-twitter"><div class="card-profile-image"><img src="' + data[i].pic + '" class="rounded-circle img-border box-shadow-1" alt="Card Image"></div>' +
'<footer class="blockquote-footer bg-twitter white"><strong>#' + data[i].screen_name + '</strong></footer></div></li>').appendTo($('#tweets-list'))
}
if (!flag) {
$('#tweet-slider').unslider({ //initialize unslider only once
autoplay: true,
arrows: true,
speed: 1000,
delay: 7000,
});
flag = true;
}
},
error: function(err) {
console.log(err);
}
}).then(function() {
setTimeout(setTweets, 8000); //Todo: Check how to do this async (dynamic adding of points)
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="card bg-twitter white">
<div class="card-content p-2">
<div class="card-body">
<div class="text-center mb-1">
<i class="ft-twitter font-large-3"></i>
</div>
<div class="tweet-slider" id="tweet-slider">
<ul id='tweets-list' class="text-center">
</ul>
</div>
</div>
</div>
Similar to .empty(), the .remove() method takes elements out of the DOM. Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.
According to this, you are removing # tweets-list as an element, I think if you use .empty () you will clean it
uses $('#tweets-list').empty();
I was reading the unslider website and it says that if you delete or add slides you should use the method slider.unslider('calculateSlides');
var flag = false;
(function setTweets() {
$.ajax({
type: "GET",
url: "../tweets/get_latest_tweets",
success: function(data) {
//clear all children first
$('#tweets-list').children().remove();
for (var i = 0; i < data.length; i++) {
$('<li>' + data[i].text + '<div class="card-footer bg-twitter"><div class="card-profile-image"><img src="' + data[i].pic + '" class="rounded-circle img-border box-shadow-1" alt="Card Image"></div>' +
'<footer class="blockquote-footer bg-twitter white"><strong>#' + data[i].screen_name + '</strong></footer></div></li>').appendTo($('#tweets-list'))
}
if (!flag) {
$('#tweet-slider').unslider('calculateSlides');
flag = true;
}
},
error: function(err) {
console.log(err);
}
}).then(function() {
setTimeout(setTweets, 8000); //Todo: Check how to do this async (dynamic adding of points)
});
})();
apparently there is no need to reinitialize the unslider, try it but, you restart it

jQuery if div id contains number from array... do something

I have an array of numbers which I need to target on pages like this:
sku = [1243,3453,6453, ..... ]
These values are inside a div on a page like this:
<div id="product_1243">
<div class="block">
test
</div>
</div>
<div id="product_3453">
<div class="block">
test
</div>
</div>
<div id="product_6453">
<div class="block">
test
</div>
</div>
I have created a function to check if a number from the array exists in this div:
sku.forEach(function (element) {
if ($("div[id*='product_item_code_" + element +"']").length) {
alert("this exists" + element);
}
});
This works, but I want to ask two questions:
1) How to use insertAfter below to insert some HTML after each <div class="block">. It should only get inserted if the statement is true of course.
$("<p>test!</p>").insertAfter(....);
2) if this is best for performance because my array is actually much much bigger with over 1000 values to check for in the forEach.
Thanks
Use append or appendTo if block is the only child of product_***
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$("<p>test!</p>").appendTo( $el );
}
or
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$el.append( "<p>test!</p>" )
}
In case block is not the only child
var $el = $("div[id*='product_item_code_" + element +"']");
if ( $el.length) {
alert("this exists" + element);
$("<p>test!</p>").insertAfter( $el.find( ".block" ) );
}
How about this? Store products instead of querying it each time as it affects performance.
const products = $('div[id^=product_item_code]')
products.each((index, element) => {
if(sku.includes(element.id.split('_')[1]))
$('.block', element).after('<p>test!</p>')
})

Check if each div has an element with a specific class inside it

I have a tree of div elements with the same class but different id as we can see below:
<div class="resultsAnalitics" id="result_0">
<span class="successResults">Success</span>
</div>
<div class="resultsAnalitics" id="result_1">
<span class="warningResults">Warning</span>
</div>
<div class="resultsAnalitics" id="result_2">
<span class="dangerResults">Danger</span>
</div>
I have to check which class exists in each of these divs and show on the console. For this I created the following code:
$( ".resultsAnalitics" ).each(function( index ) {
var current = $(this).attr('id');
console.log("I'm on div: " + current);
if($(this).has('.successResults')){
console.log('The results is success');
}
if($(this).has('.warningResults')){
console.log('The results is warning');
}
if($(this).has('.dangerResults')){
console.log('The results is danger');
}
});
I expected to get the following results like this:
I'm on div: result_0 The results is success
I'm on div: result_1 The results is warning
I'm on div: result_2 The results is danger
But I'm getting the following results:
I'm on div: result_0 The results is success The results is warning The
results is danger
I'm on div: result_1 The results is success The results is warning The
results is danger
I'm on div: result_2 The results is success The results is warning The
results is danger
How I can solve this problem?
One efficiency solution is to use .children method, because you have to check if span children of each div has one certain class.
children method gets the children of each element in the set of matched elements, optionally filtered by a selector.
$( ".resultsAnalitics" ).each(function( ) {
var current = $(this).attr('id');
console.log("I'm on div: " + current);
if($(this).children('.successResults').length){
console.log('The results is success');
}
if($(this).children('.warningResults').length){
console.log('The results is warning');
}
if($(this).children('.dangerResults').length){
console.log('The results is danger');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="resultsAnalitics" id="result_0">
<span class="successResults">Success</span>
</div>
<div class="resultsAnalitics" id="result_1">
<span class="warningResults">Warning</span>
</div>
<div class="resultsAnalitics" id="result_2">
<span class="dangerResults">Danger</span>
</div>
You were close.
The problem is that the .has() method will still return a jQuery object even if an element isn't selected. As the relevant jQuery documentation states, the .has() method will "reduce the set of matched elements to those that have a descendant that matches the selector or DOM element".
This means that your conditional statements were always true, which is why the message was logged regardless of whether any elements were found.
To check if any elements are returned from the jQuery object, check the .length property of the jQuery object in your conditional statements. In doing so, the value will be 0 when an element isn't found.
Your updated code would be:
$(".resultsAnalitics").each(function(index) {
console.log("I'm on div: " + this.id);
if ($(this).has('.successResults').length) {
console.log('The results is success');
}
if ($(this).has('.warningResults').length) {
console.log('The results is warning');
}
if ($(this).has('.dangerResults').length) {
console.log('The results is danger');
}
});
You could go the other way and target each of the classes specifically and then find the id of the parent container. Notethat I added another success div at the bottom to demonstrate that all success divs give the parent ID and then the warning and then the danger.
$(".successResults" ).each(function(){
var parent = $(this).parent().attr('id');
console.log("I'm on div: " + parent + ' - The results is success');
});
$(".warningResults" ).each(function(){
var parent = $(this).parent().attr('id');
console.log("I'm on div: " + parent + ' - The results is warning');
});
$(".dangerResults" ).each(function(){
var parent = $(this).parent().attr('id');
console.log("I'm on div: " + parent + ' - The results is danger');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="resultsAnalitics" id="result_0">
<span class="successResults">Success</span>
</div>
<div class="resultsAnalitics" id="result_1">
<span class="warningResults">Warning</span>
</div>
<div class="resultsAnalitics" id="result_2">
<span class="dangerResults">Danger</span>
</div>
<div class="resultsAnalitics" id="result_3">
<span class="successResults">Success</span>
</div>
You could use .find() (checking length of search result) and use loop to make it more elegant and elastic for further changes.
http://codepen.io/themeler/pen/mRgKLP
$( ".resultsAnalitics" ).each(function( index ) {
var $this = $(this),
current = $this.attr('id'),
states = [
{
name: '.successResults',
msg: 'The results is success'
},
{
name: '.warningResults',
msg: 'The results is warning'
},
{
name: '.dangerResults',
msg: 'The results is danger'
}
];
for (var i = 0; i < states.length; i++) {
if ($this.find(states[i].name).length) console.log("I'm on div: " + current, states[i].msg)
}
});
// Grabs all classes that end with Results within resultsAnalitics
var results = $(".resultsAnalitics span[class$='Results']");
// loop through each, grabbing parent id and innerHTML
results.each(function(idx, node) {
console.log("I'm on div:", node.parentNode.id, "- Result are:", node.innerHTML);
})
You can always use jQuery "find" method to check out for specific elements in a particular element.It returns jQuery object. Using this object we can further check for number of elements by using 'length'.
<div class="resultsAnalitics" id="result_0">
<span class="successResults">Success</span>
</div>
<div class="resultsAnalitics" id="result_1">
<span class="warningResults">Warning</span>
</div>
<div class="resultsAnalitics" id="result_2">
<span class="dangerResults">Danger</span>
</div>
<script>
$( ".resultsAnalitics" ).each(function( index ) {
var current = $(this).attr('id');
console.log("I'm on div: " + current);
if($(this).find('.successResults').length){
console.log('The results is success');
}
if($(this).find('.warningResults').length){
console.log('The results is warning');
}
if($(this).find('.dangerResults').length){
console.log('The results is danger');
}
});
</script>

DOM not updating on GET request + data-attributes

Issue: Upon updating the src of images, retrieved via GET request, the DOM never updates but their new values show in console.
Suspected Cause: I think there is some conflict with using data-attributes, but using attr() instead of data() does not seem to remedy.
HTML to be updated:
<div class="data-block">
<img data-item="hp-logo" />
<img data-item="hp-banner" />
</div>
GET Request:
if(promoid != null) {
$.get({
url: '/snippets/data.html',
cache: false
}).then(function(data){
var tempData = $('<output>').append($.parseHTML(data)).find('.data[data-promo-id="' + promoid + '"]');
myContent = tempData.html();
dataItems = $('.data-block').html();
//console.log('Data Items On Page: ', dataItems);
$(dataItems).each(function (index, value) {
if( $(this).is('[data-item]')) {
//console.log('Data Items With Attribute: ', this);
dataItemLookup = $(this).attr('data-item');
//console.log('Data Item Lookup Value: ', dataItemLookup);
$(myContent).each(function (index, value) {
//console.log('Retrieved Items Checking Against: ', this);
if ( $(this).attr('data-alias') == lastalias ) {
//console.log('Retrieved Items Match Alias: ', this);
if ($(this).attr('data-item') == dataItemLookup) {
//console.log('Retrieved Item Match', this);
dataImageDesktop = $(this).attr('data-image-desktop');
//console.log('Value to be Passed to Data Item: ', dataImageDesktop);
} else {
// Do nothing
}
} else {
// Do nothing
}
});
$(this).attr('src', dataImageDesktop);
console.log(this);
}
});
});
}
data.html:
<div class="data-container">
<div class="data" data-promo-id="11202016">
<div data-alias="test.html" data-item="hp-logo" data-image-desktop="http://placehold.it/250x150"></div>
<div data-alias="test.html" data-item="hp-banner" data-image-desktop="http://placehold.it/350x250"></div>
<div data-alias="not-test.html" data-item="hp-spot" data-image-desktop="http://placehold.it/450x350"></div>
</div>
</div>
Not sure how to proceed in troubleshooting this issue. Everything works as expected, except the DOM updating. Ideas?
Using html() on an element will get you the innerHTML of the object, which is a string. As such using it inside $() later will cause jQuery to create new elements that are not attached to the DOM. If all you are after is to select elements and modify them, simply use the $(selector) and modify it. Do not use html() and wrap the results with $().
Instead of $(selector).attr('data-name') try using $(selector).data('name') as shown in the jQuery.data() documentation.

Embedding radio buttons

I'd like to embed radio buttons inside more radio buttons, like this : https://jsfiddle.net/xa6ow1jq/
The fiddle behaves exactly like I want it to, however it seems to be a lot of code just for a 2x3 grid, and I'm planning to have at least a 3xN grid (3 layers of N buttons each, N being at least 10, but many more if the user keeps scrolling)... So I was wondering if anyone knew/could think of more efficient ways to do this. (Using php and/or javascript and/or jquery and/or jquery UI)
(I'm a javascript & jquery noob, currently (self) learning it since yesterday, so I'd appreciate if you could be gentle with technical terms and give as much explications as possible).
Thanks in advance.
The javascript code in the fiddle :
// main buttons
$(document).ready(function(){
$(".ap").click(function(){
$(".a").toggle();
$(".b").hide();
$(".c").hide();
$(".a.l").hide();
});
});
$(document).ready(function(){
$(".bp").click(function(){
$(".a").hide();
$(".b").toggle();
$(".c").hide();
$(".b.l").hide();
});
});
$(document).ready(function(){
$(".cp").click(function(){
$(".a").hide();
$(".b").hide();
$(".c").toggle();
$(".c.l").hide();
});
});
//secondary buttons
//a
$(document).ready(function(){
$(".a1").click(function(){
$(".a1.l").toggle();
$(".a2.l").hide();
$(".a3.l").hide();
});
});
$(document).ready(function(){
$(".a2").click(function(){
$(".a1.l").hide();
$(".a2.l").toggle();
$(".a3.l").hide();
});
});
$(document).ready(function(){
$(".a3").click(function(){
$(".a1.l").hide();
$(".a2.l").hide();
$(".a3.l").toggle();
});
});
//b
$(document).ready(function(){
$(".b1").click(function(){
$(".b1.l").toggle();
$(".b2.l").hide();
$(".b3.l").hide();
});
});
$(document).ready(function(){
$(".b2").click(function(){
$(".b1.l").hide();
$(".b2.l").toggle();
$(".b3.l").hide();
});
});
$(document).ready(function(){
$(".b3").click(function(){
$(".b1.l").hide();
$(".b2.l").hide();
$(".b3.l").toggle();
});
});
//c
$(document).ready(function(){
$(".c1").click(function(){
$(".c1.l").toggle();
$(".c2.l").hide();
$(".c3.l").hide();
});
});
$(document).ready(function(){
$(".c2").click(function(){
$(".c1.l").hide();
$(".c2.l").toggle();
$(".c3.l").hide();
});
});
$(document).ready(function(){
$(".c3").click(function(){
$(".c1.l").hide();
$(".c2.l").hide();
$(".c3.l").toggle();
});
});
Make formation of your html below, so you can deal with 3xN rows, you need to pop into array shown in javascript as // here and your HTML accordingly to achieve,
$(document).ready(function() {
var groups = ['a', 'b', 'c'];
// creating simple js array too use for DOM manipulation
$.each(groups, function(k, id) {
// loops groups array we just created id variable contains a, b and then c
$('#' + id).hide();
// will evaluate as $('#a').hide();
$('#' + id + 'l').hide();
// will evaluate as $('#al').hide();
});
$(".button").click(function() {
// bind click event on DOM items having class name as 'button'
var button_id = $(this).data('id');
/* $(this) will get us which button has been clicked, every
time click event occurs on DOM items having button class
and $(this).data(id); will get us clicked button's data-id attribute */
$('#' + button_id).toggle(); // toogle
var hide = $.grep(groups, function(value) {
// http://api.jquery.com/jquery.grep/
return value != button_id;
});
$.each(hide, function(k, id) {
// http://api.jquery.com/each/
$('#' + id).hide();
});
});
var selector = []; // initialize blank array
$.each(groups, function(k) {
selector.push('.' + groups[k]);
/* push groups array's elements with an extra .
so, .a .b and .c */
});
// join array elements with ,
selector = selector.join(',');
// now selector is string, having value .a,.b,.c
// https://api.jquery.com/category/selectors/
$(selector).click(function() {
// binding an event to the string we just created, follow the link above to get more idea
var button_id = $(this).data('id'); // clicked button's data-id attribute
var class_id = $(this).attr('class'); // clicked button's class
var flag = $('.' + class_id + 'l').filter('[data-id="' + button_id + '"]').is(':visible');
/* for later use, will be true if elements with matched filter conditions is visible in DOM,
false otherwise */
$.each(groups, function(k, id) {
$('#' + id + 'l').children().hide();
// https://api.jquery.com/children/
});
$.each(groups, function(k, id) {
$('#' + id + 'l').hide();
});
$('#' + class_id + 'l').show();
if (flag)
$('.' + class_id + 'l').filter('[data-id="' + button_id + '"]').hide();
else
$('.' + class_id + 'l').filter('[data-id="' + button_id + '"]').show();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="button" data-id="a">Toggle a</button>
<button class="button" data-id="b">Toggle b</button>
<button class="button" data-id="c">Toggle c</button>
<div id="a">
<div class="a" data-id="1"><button>Toggle a1</button></div>
<div class="a" data-id="2"><button>Toggle a2</button></div>
<div class="a" data-id="3"><button>Toggle a3</button></div>
</div>
<div id="b">
<div class="b" data-id="1"><button>Toggle b1</button></div>
<div class="b" data-id="2"><button>Toggle b2</button></div>
<div class="b" data-id="3"><button>Toggle b3</button></div>
</div>
<div id="c">
<div class="c" data-id="1"><button>Toggle c1</button></div>
<div class="c" data-id="2"><button>Toggle c2</button></div>
<div class="c" data-id="3"><button>Toggle c3</button></div>
</div>
<div id="al">
<div class="al" data-id="1">this is line a1</div>
<div class="al" data-id="2">this is line a2</div>
<div class="al" data-id="3">this is line a3</div>
</div>
<div id="bl">
<div class="bl" data-id="1">this is line b1</div>
<div class="bl" data-id="2">this is line b2</div>
<div class="bl" data-id="3">this is line b3</div>
</div>
<div id="cl">
<div class="cl" data-id="1">this is line c1</div>
<div class="cl" data-id="2">this is line c2</div>
<div class="cl" data-id="3">this is line c3</div>
</div>

Categories