add data to element in each function - javascript

I made an each function that counts the images inside a div and I am trying to set the number of images counted inside the div as a data attribute for the div but it is not working.
Have I gone about this the wrong way because it does not seem to be working?
Here is the site http://www.touchmarketing.co.nz/test/
var mostImages = 0;
numSliders = $wowSlides.length,
lastVindex = numSliders-1;
$wowSlides.each(function(){
var $this = $(this),
$images = $this.find('img'),
numImages = $images.length;
$images.css({width:$slideWidth, 'float':'left', 'position':'relative'}).wrapAll('<div class="slider" />');
$slider = $this.find(".slider");
$slider.width($slideWidth*numImages).css({'float':'left'});
$this.data('count', numImages); // add data-count="insert number here" to this .wowSlides div
console.log(numImages);
if(numImages > mostImages){
mostImages = numImages;
}
});

This sets data to jQuery's proprietary data cache:
$this.data('count', numImages);
It doesn't set to a data- attribute of the element. Generally there shouldn't be a need to set a data- attribute on the client, since its purpose is to transfer data from server to client.
Nevertheless, if you want to set it, use
$this.attr('data-count', numImages)
or
this.setAttribute('data-count', numImages)
Personally, if I wanted to associate a small amount of data with an element, I'd just store it as a property directly on the element itself.
this.count = numImages;
For primitive data, it's harmless. For larger objects or other DOM elements, I'd be more hesitant.

Related

Copy text from div innerHtml to textarea

A connected question to this problem with the iframe issue:
Copy div from parent website to a textarea in iframe
I'm trying to copy InnerHtml from a div to a TextArea.
I've made two instances of google translator on the same web page, and I'm trying to apply auto-correction of the first instance to the second instance, without changing the first textarea.
I tried different code:
setInterval(function() {
childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
$("#source")[1].val(childAnchors1.text());
}, 100);
setInterval(function copyText() {
$(".goog-textarea short_text")[1].val($("#spelling-correction > a")[0].innerText());
}
, 100);
setInterval(function copyText() {
$("#source")[1].val($("#spelling-correction > a")[0].innertext());
}
, 100);
setInterval(function() {
var finalarea = document.getElementsByClassName("goog-textarea short_text")[1];
var correction = document.querySelectorAll("#spelling-correction > a")[0].innerHTML
document.getElementsByClassName("goog-textarea short_text")[1].value = correction.innerText;
}, 100);
onclick='document.getElementsByClassName("goog-textarea short_text")[1].innerHTML=document.getElementById("spelling-correction > a")[0].innerHTML;'
But nothing of that seems to work, unfortunately...
I would be very grateful for any help.
I should have mentioned this. I used iframe to create the second instance, so simple solutions don't work...
This is the code I used for creating iframe instance:
var makediv = document.createElement("secondinstance");
makediv.innerHTML = '<iframe id="iframenaturalID" width="1500" height="300" src="https://translate.google.com"></iframe>';
makediv.setAttribute("id", "iframeID");
var NewTranslator = document.getElementById("secondinstance");
var getRef = document.getElementById("gt-c");
var parentDiv = getRef.parentNode;
parentDiv.insertBefore(makediv, getRef);
I tried to use this to communicate between the iframe and the parent website:
setInterval(function() {
var childAnchors1 = window.parent.document.querySelectorAll("#spelling-correction > a");
var TheiFrameInstance = document.getElementById("iframeID");
TheiFrameInstance.contentWindow.document.querySelectorAll("#source").value = childAnchors1.textContent;
}, 100);
But it doesn't work...
Ok, I made it work with:
var a = document.createElement('iframe');
a.src = "https://translate.google.com";
a.id = "iframenaturalID";
a.width = "1000";
a.height = "500";
document.querySelector('body').appendChild(a)
And
let iframe = document.getElementById("iframenaturalID");
setInterval(function() {
let source = iframe.contentWindow.document.getElementById("source");
let destination = window.parent.document.querySelector("#spelling-correction > a");
source.value = destination.textContent;
}, 100);
Now it does what I tried to do, however I still get mistake message: Uncaught TypeError: Cannot set property 'value' of null
at eval, which points at this line: source.value = destination.textContent;. It's not a big problem though, but still it's strange that it returns this mistake...
Ok, I was able to solve it by adding setTimeout.
Since a textarea is a form element, neither .innerText or .innerHTML will work. You need to extract its content with the value property (or .val() with JQuery).
And FYI:
It's innerText, not .innertext.
.innerText is a property, not a function, so you don't use () after it.
It's .innerHTML, not .innerHtml.
innerHTML is used when there is HTML in the string that should be
parsed as HTML and .textContent is used for strings that should not
be parsed as HTML. Usually, you don't map the contents of one to the
other.
document.querySelectorAll() scans the entire DOM to find all
matching nodes. If you know you only have one matching node or you
only want the first matching node, that's a waste of resources.
Instead, use .querySelector(), which stops searching after the
first match is found.
Since you are using JQuery, you should be consistent in its use. There's no need for .querySelector() or .querySelectorAll() with JQuery, just use JQuery selector syntax.
Here's an example that shows both the vanilla JavaScript and JQuery approaches using the HTML types that you show in your question with the same id values and nesting structure that you show. You can see that I'm using different selectors to correctly locate the input/output elements.
// Standare DOM queries to get standard DOM objects
let source = document.getElementById("source");
let destination = document.querySelector("#spelling-correction > a");
// JQuery syntax to get JQuery objects:
let jSource = $("#source");
let jDestination = $("#spelling-correction > a");
// Vanilla JavaScript way to set up the event handler and do the work
source.addEventListener("keyup", function(){
destination.textContent = source.value;
});
// JQuery way to set up the event handler and do the work
jSource.on("keyup", function(){
jDestination.text(jSource.val());
});
textarea, div {
border:3px solid grey;
width:500px;
height:75px;
font-size:1.5em;
font-family:Arial, Helvetica, sans-serif;
}
.destination { pointer-events:none; background:#e0e0e0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Type in the first textarea</p>
<textarea id="source"></textarea>
<div id="spelling-correction">
Did you mean:
</div>
The problem in all the codes you've tried is how to get the text correctly.
Starting with your First example it should be using innerText instead of text() since it's a jquery object and you're returning a DOM object not a jQuery object:
setInterval(function() {
childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
$("#source")[1].val(childAnchors1.innerText);
}, 100);
In your Second example and Third one, you need to remove the parentheses from the innerText like:
setInterval(function copyText() {
$(".goog-textarea short_text")[1].val($("#spelling-correction > a")[0].innerText);
}, 100);
I suggest the use of pure js and textContent attribute like:
setInterval(function() {
var childAnchors1 = document.querySelectorAll("#spelling-correction > a")[0];
document.querySelectorAll("#source")[1].value = childAnchors1.textContent;
}, 100);
NOTE: I should point that your HTML code in invalid since you're using duplicate identifier when the id attribute should be unique in the same document.

Can't change html attribute via javascript

This is very odd, I'm getting videos via document.getElementsByTag('video') and I can't change their width nor any other value.
Here's the Javascript code I'm using -
window.onload = function() {
this.videos = document.getElementsByTagName('video');
var self = this;
for(var i=0;i<videos.length;i++) {
videos.item(i).addEventListener("loadedmetadata",
(function(index){
return function() {
console.log(self.videos[index].offsetWidth); //shows X
self.videos[index].offsetWidth = "480";
console.log(self.videos[index].offsetWidth); //shows X
}
})(i)
);
}
}
Example <video> tag -
<video><source src="videos/video_1.mp4" type="video/mp4"></video>
I have no idea what it is happening and I've never encountered such kind of problem.
Thanks
EDIT:
Using the setAttribute function just adds it to the live html, but the size isn't really changing
The offsetWidth is a read-only DOM property so you can not update it. However why not change the element width?
window.onload = function() {
this.videos = document.getElementsByTagName('video');
var self = this;
for(var i=0;i<videos.length;i++) {
videos.item(i).addEventListener("loadedmetadata",
(function(index){
return function() {
self.videos[index].width = "480";
}
})(i));
}
}
You can take into account the borders, paddings, margins...
Note there is a difference between three things you are conflating into one:
HTML attributes
DOM properties
CSS styles
This is an HTML attribute:
If you have a DOM element representing an HTML tag, you can modify the attributes like so:
var a = document.createElement('a')
a.setAttribute('href', "http://example.com")
This is a DOM property:
var a = document.createElement('a')
a.href = "http://example.com"
Note how a DOM property can be similarly named to an HTML attribute, but they are not the same thing. Oftentimes, changing an HTML attribute will modify the corresponding DOM property, but not vice versa. Also, not all attributes have matching properties, and so on.
CSS styles are accessed via the DOM property style(which corresponds to the HTML attribute style, but while the HTML attribute style is a string, the DOM property is an object):
var a = document.createElement('a');
a.style.width = "500px";
a.style.height = "20%";
There are HTML attributes "width" and "height", but their use is deprecated in favor of using styles. Also, "width" and "height" as HTML attributes can only be numerical values representing pixels - while a CSS style can be many variations(pixels, ems, percentages, etc)
In your specific case, just modify the width styling of your element to change its width.
Another thing in your code is the usage of this and self, which is entirely unneeded. this.videos is setting a property on the global object(window) for no reason. You can also avoid closing over the index property by using .bind():
window.onload = function() {
var videos = document.getElementsByTagName('video');
for (var i = 0; i < videos.length;i++) {
var video = videos.item(i);
video.addEventListener("loadedmetadata", (function () {
console.log(this.offsetWidth);
this.style.width = "480px";
console.log(this.offsetWidth);
}).bind(video));
}
}
Try using getAttribute and setAttribute, as in videos[index].setAttribute('offsetWidth', 480)
First off, this doesn't seem right:
for(var i=0;i<videos.length;i++) {
Shouldn't it be self.videos? Fix that.
Then, to change the video size, you can change the size of the element:
self.videos[index].width = "480";
or, even better, the CSS width:
self.videos[index].style.width = "480px";
The size of the video itself will automatically extend to the size of the video element.

Add a js function to the DOM?

I have a very simple HTML page. After everything is loaded, the user can interact with it perfectly. Now, at some point, the user clicks on an element. An ajax call is made and new data is being requested. I now want to remove the previous element the user clicked on with the element(s) the user has requested (on the same page) - practically remove the old element from the DOM and add the new one. Well, I did this as well, but I am unable to add a function to the newly created element. This is my function:
setCountry = function(value){
document.getElementById('country').innerHTML = value;
}
and I'm trying to add it like this to my element
a_tag.setAttribute("href", "javascript:setCountry(countries[i]);");
The function is being called and writes "undefined" to the innerHTML element. I set the attribute using a for loop and just above the for loop I alert an element from the array to be sure it's correct, and it prints out the correct value.
I assume the problem happens because the function is being created on the first load of the DOM, but I'm not sure. Can anyone shed some light on what is really happening here and what I should do to correct it? I want to be able to add more functions so not looking for a work around writing an innerHTML tag, I just want to understand what I'm doing wrong.
Thank you.
Edited with more code
//declare an array to hold all countries form the db
var countries = new Array();
function getCountries(region) {
document.getElementById('scroller').innerHTML = '';
//send the data to the server and retreive a list of all the countries based on the current region
$.ajax({
type: "POST",
url: "scripts/get_countries.php",
data: {
region: region
},
success: saveDataToArray,
async: false,
dataType: 'json'
});
//save the data to an array
function saveDataToArray(data){
var i = 0;
while (data[i]){
countries[i] = data[i];
i++;
}
}
scroller = document.getElementById('scroller');
//create a ul element
var holder = document.createElement("ul");
//here create a back button which will recreate the whole list of regions
var total = countries.length;
for(i=0;i<total;i++){
//create the first field in the list
var bullet_item = document.createElement("li");
//create an a tag for the element
var a_tag = document.createElement("a");
//set the redirect of the tag
a_tag.setAttribute("href", "javascript:setCountry(this);");
//create some text for the a_tag
var bullet_text = document.createTextNode(countries[i]);
//apend the text to the correct element
a_tag.appendChild(bullet_text);
//apend the a_tag to the li element
bullet_item.appendChild(a_tag);
//apend the item to the list
holder.appendChild(bullet_item);
}
//apend the holder to the scroller
scroller.appendChild(holder);
}
function setRegion(region){
document.getElementById('region').innerHTML = region;
}
setCountry = function(value){
document.getElementById('country').innerHTML = value;
}
There is no need for quoting the code in a string. Instead of this:
a_tag.setAttribute("href", "javascript:...")
Try to form a closure:
a_tag.onclick = function () { ... }
Note that by default <A> elements without HREF do not look normal, but you can fix that with CSS.
Problem solved
Everything was good apart from the way I was declaring the href parameter
a_tag.setAttribute("href", "javascript:setCountry("+'"'+countries[i]+'"'+")");
it's all the usual, a game of single quotes and double quotes.
Thanks everyone for pitching in ideas. Much appreciated as usual
Adrian

find <img> tag inside text string

I have an xml document (from a feed), which I'm extracting values from:
$(feed_data).find("item").each(function() {
if(count < 3) {
//Pull attributes out of the current item. $(this) is the current item.
var title = $(this).find("title").text();
var link = $(this).find("link").text();
var description = $(this).find("description").text();
Now inside "description" i need to get the img element, but this is causing me some problems. "descripttion" is a regular string element and it seems i can't call the ".find()" method on this, so what do i do?
I have tried calling .find():
var img = $(this).find("description").find("img");
But it's a no go. The img is wrapped in a span, but I can't get to this either. Any suggestions? I'd prefer to avoid substrings and regex solutions, but I'm at a loss.
I've also tried turning the "description" string into an xml object like so:
var parser = new DOMParser();
var desc = parser.parseFromString(test,'text/xml');
$(desc).find("img").each(function() {
alert("something here");
});
But that doesn't work either. It seems like it would, but I get a "document not well formed" error.
Try enclosing the contents of the description tag in a dummy div, that seemed to work better for me, and allowed jQuery's .find() to work as expected.
e.g.
$(feed_data).find("item").each(function() {
if(count < 3) {
//Pull attributes out of the current item. $(this) is the current item.
var title = $(this).find("title").text();
var link = $(this).find("link").text();
var description = '<div>' + $(this).find("description").text() + '</div>';
var image = $(description).find('img');
Hi and thanks for the prompt replies. I gave GregL the tick, as I'm sure his solution would have worked, as the principle is the same as what I ended up with. My solution looks like this:
$(feed_data).find("item").each(function() {
if(count < 3) {
//Pull attributes out of the current item. $(this) is the current item.
var title = $(this).find("title").text();
var link = $(this).find("link").text();
var description = $(this).find("description").text();
var thumbnail = "";
var temp_container = $("<div></div>");
temp_container.html(description);
thumbnail = temp_container.find("img:first").attr("src");
So wrap the string in a div, and then use "find()" to get the first img element. I now have the image source, which can be used as needed.
maybe you should try to convert the description text to html tag and then try to traverse it via jquery
$('<div/>').html($(this).find("description").text()).find('img')
note: not tested

How can I select an HTML element from JavaScript without knowing its ID?

I have an unknown number of <img> elements on my page with no IDs, and I need to be able to browse through them and set certain attributes based on a number of unpredictable factors.
You would use this function to browse through them as an array:
document.getElementsByTagName('img');
This is an array of img elements, and you can treat it as if you were using the getElementById() function (i.e. you can still do the same operations on the elements, but you need to reference an element):
document.getElementsByTagName('img')[0]
If the factors you are speaking about are really complicated, I would use jQuery (it's really powerful):
$('img[alt]').css('padding', '10px');
This would add a 10px padding to every image with an alt attribute (I hope, as I'm notorious for posting almost-working code).
Good luck!
Everyone forgets about document.images...
for(var i = 0; i < document.images.length; i++) {
var img = document.images[i];
if(img.src == "banner.gif") {
img.alt = "Banner";
}
else if(img.alt == "Giraffe") {
img.title = "15 feet tall!";
}
}
If you need to get images within another element, you can use getElementsByTagName...
var elem = document.getElementById('foo');
var fooImages = elem.getElementsByTagName('img');
Use document.getElementsByTagName():
var imgs = document.getElementsByTagName("img");
for(var i = 0; i < imgs.length; i++) {
var currentImg = imgs[i];
if (currentImg.somAttr) {
// do your stuff
}
}
You can use getElementsByTagName to get a list of the img tags:
https://developer.mozilla.org/en/DOM/element.getElementsByTagName
You can set name attribue for image tag and can perform any operation using document.getElementsByName.
for example
<script type="text/javascript">
function getElements()
{
var x=document.getElementsByName("x");
alert(x.length);
}
</script>
<input name="x" type="text" size="20" /><br />
<input name="x" type="text" size="20" />
Use jQuery and search by element type $("img").each() to perform am operation on each element
jQuery is probably your best bet. Otherwise you'll have to traverse a dom tree and check for attributes manually. Once you use jQuery you can select elements by attributes like name, class, the tag name (input, image, etc) and combinations of them.
$("image .className").attr(....
http://www.jquery.com
It's hard to answer this without knowing more specifics, but have you considered using Jquery?

Categories