.map() img src attribute undefined - javascript

Ok so I want to .map() the src values of the html content of #stage to the variable srcArray
var content = $('#stage').html();
var srcArray = $.map($(content), function(el) {
return {value: $(el).children().attr('src')};
});
but when I console.log the array, each src value comes up as undefined. Anyone know what's up?
html is
<div id="stage">
<div style="left:xxx, top:xxx">
<img src="xxxxx" style="width:xxx, height:xxx"/>
</div>
</div>
Do I need to convert the src value to a string to have it show up on the chrome console?

You could get all the img from the #stage element.
var srcArray = $('#stage').find('img').map(function() {
return { value: $(this).attr('src') };
}).get();

Problem :
1. statement return {value: $(el).children().attr('src')}; Will execute for each children of 'div#stage' but stage also have a
div which doesn't have any src attribute.
2. In case 'div#stage'have multipleimg` elements then above statement will return only one result
3. Statement $(content) creating new html elements .Never create new content if you just want to treverse (A bad practice).
Solution :
1. Filter children so that only img tag will be selected.
2. Map on children('img') so that if there are more than 1 img element,code will be executed for each img
3. Use $('#stage') instead of $(content) (which is creating new html elements)
Try this-
var content = $('#stage').html();
var srcArray = $.map($(content).children("img"), function (el) {//better way use $.map($('#stage').children("img"), function (el) {
return {
value: $(el).attr('src')
};
});
console.log(JSON.stringify(srcArray))
Update:-
DEMO

Well the issue is with your children() selection and reading the attribute. It will read the attribute of the first child. So if the first child does not have the attribute it will be undefined. So you need to actually select the element you want. It is also weird you are selecting the html and than building a nodeset based on that html. Just do the selection and use map
var srcArray = $('#stage [src]').map(
function () {
return { value: $(this).attr('src')};
}
);

Related

Problem with access to dynamically created elements

I've asked a similar question before but that was about events related to dynamically created elements. Now I just want to change class lists of dynamically created img tags in a div. Here is what is all about, I want to create a slider that contains three images taken with src and alt attributes taken from a JSON file. Function created all three normally and as I wanted put displayNone class on every img except first. Another function should on every 3 seconds check in a loop all the dynamically created img tags for the one that does not contain displayNone class and to add to that particular img class displayNone and then to get next, or if it is last first, img and to remove his displayNone class. I created var inside function to get an array of these images. Does anybody know what the solution is?
function showSlides(slidesJsonData){ // there is no problem with this function it generates img tags when window is loaded
var writingSlides = "";
for (slide in slidesJsonData){
if(slide==0){
writingSlides += `<img src="${slidesJsonData[slide].src}" alt="${slidesJsonData[slide].alt}"/>`;
}
writingSlides += `<img class="displayNone" src="${slidesJsonData[slide].src}" alt="${slidesJsonData[slide].alt}"/>`;
}
document.querySelector("#slider").innerHTML=writingSlides;
}
function slideShow(){
var images = document.querySelectorAll("#slider img");
images.forEach((img,index) => {
if(index<images.length-1){
if(!img.classList.contains("displayNone")){
img.classList.add("displayNone");
img[index+1].classList.remove("displayNone");
}
}
else {
img.classList.add("displayNone");
document.querySelector("#slider img:first-of-type").classList.remove("displayNone");
}
});
setTimeout("slideShow()",3000);
}
slideShow();
Now error is:
Uncaught TypeError: Cannot read property 'classList' of undefined
at main.js:73
at NodeList.forEach (<anonymous>)
at slideShow (main.js:69)
at <anonymous>:1:1
try updating your sliderImages variable before accessing it because it probably is being created before content as finished loading
You are using a for in loop that exposes other enumerable properties of the element collection unrelated to element indexing. Element collections are not proper arrays but rather are array-like objects
When you try to pass these properties to sliderImages[sliderImage] inside your loop they do not return an element with a classList property and no sub property contains which throws the error.
Use a for loop based on length or a for of loop or sliderImages.forEach(callback)
Simple property output example of the for in
const li = document.querySelectorAll('li')
for (let x in li) {
if (isNaN(x)) {
console.log(`Property "${x}" is not an element index`)
} else {
console.log(`Key "${x}" is an element index`)
}
}
<ul>
<li></li>
<li></li>
</ul>
Try this
var images = document.querySelectorAll("#slider img");
let cnt= 0
function slideShow(){
images[cnt].classList.toggle("displayNone")
cnt++
if (cnt>= images.length) cnt = 0;
images[cnt].classList.toggle("displayNone")
}
setInterval(slideShow,3000);

get second element by class name if it exists

I'm trying to get the ID of an element by class name like this
var prod_id2 = document.getElementsByClassName('select-selected')[1].id
document.getElementById('hidden-input-2').value = prod_id2;
This works fine, but my issue is that if there's only one element with that class it breaks the functionality, so I need some sort of if statement to only define this var if there is a second div with that class.
Any ideas?
Try this:
const elements = document.querySelectorAll('.test');
if (elements[1]) {
elements[1].innerText = 'Hithere';
}
<div class="test">hi</div>
<div class="test">hi</div>
<div class="test">hi</div>
document.querySelectorAll('.test'); selects all elements with the class test and returns a nodelist.
Then we can access the second element via of the nodelist with elements[1].
Here is how to check for the second element.
You can also set another fallback , different to null:
document.addEventListener("DOMContentLoaded", function(event) {
var selectedElements = document.querySelectorAll('.selected-selected'),
prod_id2 = selectedElements[1] || null;
alert(prod_id2)
});
<div id="test" class="selected-selected"></div>
You can also check that value then:
if (prod_id2) { // do some other stuff with the set value }
It breaks the functionality I think because you are grabbing the 2nd element specifically. You can do:
const prod_id2 = document.querySelectorAll('.select-selected');
and loop over the elements and grab the ID
prod_id2.forEach((prod, index) => {
if(index === 2) {
document.getElementById('hidden-input-2').value = prod.id;
}
})

Get child element without id or class attributes with AngularJS

I have the following HTML code :
<div id="someId">
<div ng-transclude>
</div>
</div>
Really simple I am getting the div element which has ID attribute using the following function :
var getElementById = function (id) {
return angular.element("#" + id);
};
Where in this example case the ID is 'someId'. My goal is to get the div inside the one I just got. So I want to return the div with ng-transclude attribute. I believe that this will happen by getting an element by attribute name or something.
Thanks in advance.
PS: I can't put any other attributes in the div I wanted(like id) because in the real life it is far more complecated and the code is auto-generated.
I think this will help you
var getElementByAttribute = function (attribute) {
return angular.element(document).find('[' + attribute + ']');
};
var el = getElementByAttribute('ng-transclude')
I don't know if that will be the Angular way, but you can use native properties of the HTML element. Something like this:
var getElementById = function (id) {
return angular.element("#" + id);
};
var childDivWithTransclude = getElementById('someId').children[0];

Insert HTML after certain paragraph of HTML string

I've got a HTML-string I'd like to render but append some HTML after the 2nd paragraph first.
function insertStuff() {
//var string = "<div><p>paragraph 1</p><p>paragraph 2</p><p>paragraph 3</p></div>"; works
var string = '<p><img src="http://example.com/my-cool-picture.png" alt="alt text"></p><p>2nd paragraph</p><p>3rd paragrpah</p>' // doesn't work
var parsedHtml = $(string)
parsedHtml.find("p:nth-child(2)").after("<p>My cool insert</p>")
return parsedHtml.html()
}
This works for the HTML string above but the following one only return the <img> after invoking parsedHtml.html()
What am I doing wrong?
Since you are use .html() it will return html of first element.
You can wrap your content in a div like
var parsedHtml = $('<div />').html(string)
Then your code will work.
function insertStuff() {
var string = '<p><img src="http://example.com/my-cool-picture.png" alt="alt text"></p><p>2nd paragraph</p><p>3rd paragrpah</p>'
var parsedHtml = $('<div />').html(string)
parsedHtml.find("p:nth-child(2)").after("<p>My cool insert</p>")
return parsedHtml.html()
}
alert(insertStuff())
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Try this
function insertStuff() {
var string = '<div><p><img src="http://example.com/my-cool-picture.png" alt="alt text"></p><p>2nd paragraph</p><p>3rd paragrpah</p></div>';
var parsedHtml = $(string)
parsedHtml.find("p:nth-child(2)").after("<p>My cool insert</p>")
return parsedHtml.html()
}
You should put this string in a div as parent.
That's because html method as getter returns html content of the first element in the set. You should either wrap all the top-level elements in the set with another element and read it's html content or iterate through the set and concatenate each element's outerHTML property.
parsedHtml.map(function() { return this.outerHTML; }).get().join('');
If you want to get the innerHTML of all the elements in the set, replace outerHTML with innerHTML.
when you use find() with a selector it will search inside that selector (in child nodes) that why when you use string with div tag you are getting the desired result and when you delete div the problem occured

Why does jQuery, outputs same rel each time?

so basically here is my script:
http://jsfiddle.net/JJFap/42/
Code -
jQuery(document).ready(function() {
var rel = new Array();
var count = 0;
jQuery(".setting").each(function() {
rel[count] = [];
if(jQuery("span").attr("rel")) {
rel[count].push(jQuery("span").attr("rel"));
}
console.log(count);
count++;
});
jQuery("body").text(rel);
console.log(rel);
});​
and
<div class="setting">
<span rel="Variable">Variable</span>
<span rel="Item">Item</span>
<span rel="Something">Something</span>
</div>
<div>
<span rel="Smth">Smth</span>
<span>Sec</span>
</div>
<div class="setting">
<span>Second</span>
<span rel="first">First</span>
<span rel="Third">Third</span>
</div>
​my question, is why does it display Variable, variable?
I would like it to display Variable, First, but I'm not able to do.
Basically what I would like to achieve is create new array, in which insert each div.setting span elements with rel attribute array.
So basically in this example it should output -
Array (
Array[0] => "Variable","Item","Something";
Array[1] => "first","Third";
)
Hope you understood what I meant :)
EDIT:
In my other example I tried to add jQuery("span").each(function() ... inside first each function, but it outputted two full arrays of all span elements with rel. I can't have different classes / ids for each div element, since all will have same class.
jQuery('span') is going to find ALL spans in your page, and then pull out the rel attribute of the first one. Since you don't provide a context for that span search, you'll always get the same #1 span in the document.
You should be using this:
jQuery('span',this).each(function() {
rel[count] = [];
if (jQuery(this).attr("rel")) {
rel[count].push(jQuery(this).attr("rel"));
}
console.log(count);
count++;
})
instead of this:
rel[count] = [];
if(jQuery("span").attr("rel")) {
rel[count].push(jQuery("span").attr("rel"));
}
console.log(count);
count++;
http://jsfiddle.net/mblase75/JJFap/52/
The trick is to use a second .each to loop over all the span tags inside each <div class="setting"> -- your original code was using jQuery("span"), which would just grab the first span tag in the document every time.
In addition to what has been said, you can also get rid of the count and one push() when using jQuery.fn.map() as well as getting rid of the if when adding [rel] to the selector:
jQuery(document).ready(function() {
var rel = [];
jQuery(".setting").each(function() {
rel.push(jQuery(this).find('span[rel]').map(function() {
return this.getAttribute('rel');
}).get());
});
jQuery("body").text(rel);
console.log(rel);
});
Within the .each() method, you have this code a couple times: jQuery("span").attr("rel"). That code simply looks for ALL span tags on the page. When you stick it inside the .push() method, it's just going to push the value for the rel attribute of the first jQuery object in the collection. Instead, you want to do something like $(this).find('span'). This will cause it to look for any span tags that are descendants of the current .setting element that the .each() method is iterating over.

Categories