I have a function ImageIndexing(type,data) that will return a string according to the two variables. Than I have classes: portoflioTitle, portfolioThumbnail, portoflioBig; and I need to change their content, src, id accordingly to their data-title, data-thumb and data-big. Its really hard to explain, so let me try.
So:
After the page loads a function is executed.
First, the function changes the innerHTML (content) of all the divs with class portfolioTitle. It changes it trough the ImageIndexing function to which it passes 'title' as the type and its data-title as the data. The ImageIndexing function will then return the string we need to change the innerHTML to. (can you understand it so far?)
It repeats the same with the other classes. With portfolioThumbnail it passes 'image' as the type and its data-thumb as the data and than sets the returned string to its src. portfolioBig passes 'big' and data-big and uses the string as its id.
Edit: You should use .attr to get the value of the element. Updated jsFiddle here
I am not sure what you really want, but from your comment I believe you want to know hwo to pass data-x and set the innerHTML of the corresponding div.
Below is just rough version, let us know if you have any questions.
$('div.portoflioTitle').each (function(index) {
$(this).html(ImageIndexing(this.title, $(this).attr('data-title')));
});
function ImageIndexing(type, data) {
//do w.e you have to do and return
return "<span>can return anything that you wanna set inside the div</span>";
}
Related
With JavaScript, one often want to use the e.g. getElementById() function to search for a HTML-tag with a specific ID and return it's innerHTML values.
However, is it possible to achieve the opposite?
<tag1 id="myID1">
<tag2 id="myID2">
<tag3>myText</tag3>
</tag2>
</tag1>
I want to create a function which is looking for the first appearance of "myText" as a innerHTML text and returning it's upper most parent tag id. In this case, if I search for "myText", I expect to return "myID1". How can JavaScript achieve that?
To scan through the children of an html element you could use a recursive function something like:
function findInnerHTMLMatch(s,e){
if (e.innerHTML===s) return e;
for (let n=0;n<e.children.length;n++){
const rtn=findInnerHTMLMatch(s,e.children[n]);
if (rtn) return rtn;
}
}
then if you want to find on the whole page just call findInnerHTMLMatch('myText',document.body).
This will return the DOM element containing exactly and only the text you specify.
After that I find your requirements unclear. If you are seeking the ultimate parent element then, logically, you will end up with the <html> element every time. So, are you after the top element with an id defined? If not what else and, perhaps most importantly as this will help clarify things, why?
Just because I enjoy thinking about these things... If you want to do it without recursion, a stack works well and is possibly more elegent:
function findInnerHTMLMatch(s,e){
const stack=[e];
while (stack.length){
const el=stack.pop();
if (el.innerHTML===s) return el;
stack.push(...el.children);
}
}
I have the following code, which preprocesses some response data from an AJAX call before displaying it (the displaying part is not shown). In particular, it sets the src attribute of the image in each li element of the response.
$(response.items).filter('li').each(function(i){
$('img', this).attr('src', 'images/Picture.jpg');
if (i==0){
console.log(this);
console.log(response.items);
}
});
The output of console.log(this) shows that the src attribute gets set correctly in the context represented by this, but the output of console.log(response.items) shows that response.items is unchanged.
Is there a (preferably non-hacky) way to persist all changes to the li elements to response.items?
I think the problem here is that you're using the filter method. Filter (and also map) don't modify the original array, they essentially make a copy of it. So if you would check the return value of this whole code block like this:
var processed = $(response.items).filter('li').each(function(i){
$('img', this).attr('src', 'images/Picture.jpg');
if (i==0){
console.log(this);
}
});
console.log(processed);
It should properly show the changed values. Depending on what you want to do you could also use a map method after the each.
I select an element of the page:
$mainSection = $('#main');
then I add more Elements via AJAX into the <div id="main"></div> element. Next time I call $mainSection, the newly added elements are also in it. But I don't want that. I would like that the variable $mainSection only has the content in it from the initial rendering of the page. I can't find a way to prevent jQuery from updating.
I tried this:
$(document).ready(function(){
$mainSection = $('#main').clone(true);
Then I add new elements to #main and then I check if they get found via:
$foundElement = $($mainSection + ":not(:has(*)):not(script):contains('"+newlyAddedContent+"')");
On page load, they are not there. But after I add them, they get found.
I also tried:
$mainSection = $('#main').html();
$mainSection = $($mainSection);
didn't work also.
Here is a jsFiddle to illustrate my point:
http://jsfiddle.net/VEQ2E/2/
The problem is somewhere burried in this line:
$foundElement = $($mainSection + ":not(:has(*)):not(script):contains('"+newlyAddedContent+"')");
It somehow always searches through the whole document, when I do it like this.
You can use .clone(true):
$mainSection = $('#main').clone(true);
It every time takes the clone/copy of the initial state of this div.
Note:
.clone( [withDataAndEvents ] [, deepWithDataAndEvents ] )
withDataAndEvents : Boolean (default: false)
deepWithDataAndEvents : Boolean (default: value of withDataAndEvents)
A Boolean indicating whether event handlers and data for all children of the cloned element should be copied.
Your problem was not that your clone was getting changed, but rather the selector you were using to try finding something within the clone. Your code was like this:
$($mainSection + ":not(:has(*)):not(script):contains('"+newlyAddedContent+"')");
Concatenating an object with a string will turn the object into a string, simply "[object Object]", then your selector will just look at the ":not(:has..."
Instead, you should use filter:
$foundElement = $mainClone.filter(":not(:has(*)):not(script):contains('world')");
This will now only look within your $mainClone for items matching that filter.
JSFiddle
You can take several approaches:
Cache the contents of #main before the update. This gives you just the contents of the element without the element.:
mainsectionContents = $('#main').html();
Or Cache a copy of #main before the update. This will give you the content together with the element, and depending on whatever else you may want to copy feel free to check the api docs:
$mainsectionCopy = $('#main').clone();
Please, do not laugh, too much. I know jQuery ans JS for a short a while.
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
For the first one, why do you need a selector like that? couldn't you find something less specific to hook onto? If you must keep it when joining an number and a string, JavaScript will convert the number to string behind the scenes so you don't really need the .toString() and could do the "maths" +/-1 outside of your selector making it more readable.
Edit
In regards to your comment I am not really sure what you mean, you could assign a class to the "post" items and then add the unique id to a data-attribute ID. To make it simpler you could do something like this:
var codeLt = aktywneZdanie + 1,
codeGt = aktywneZdanie - 1;
$('code:lt(' + codeLt + '):gt(' + codeGt +')').removeClass('class2');
End Edit
And the second solution should work, all your doing is passing the dom elements found from your selector into a function as a jQuery "array" in which manipulate to your needs
And for your second question why not just toggle the class on and off? having a default state which reflects class one?
jQuery('#something').toggleClass('uberClass');
Or you can pass your selector to the function
changeClasses(jQuery('#something'));
Then inside you function work on the return elements.
Edit
Your code should work fine, but id suggest checking to make sure you have got and element to work on:
changeClasses(jQuery('#something'));
function changeClasses($element){
if($element.length > 0) {
$element.addClass('class1');
}
}
End Edit
Hope it helps,
1) How can I make this code more efficient? First line is how do I "select" elements, the second, line is how do I prep to "select", next or previous element.
jQuery('code:lt('+((aktywneZdanie+1).toString())+'):gt('+((aktywneZdanie-1).toString())+')').removeClass('class2');}
aktywneZdanie=aktywneZdanie-1
I stoped creating this wierd code like this one above, instead I start using .slice() (do not forget to use .index() for arguments here), .prev(), .next(). Just those three and everything is faster and clearer. Just an example of it below. No it does not do anything logical.
var activeElem = jQuery('code:first');
var old Elem;
jQuery('code').slice('0',activeElem.index()).addClass('class1');
oldElem=activeElem;
activeElem=activeElem.next();
jQuery('code').slice(oldElem.index(),activeElem.index()).addClass('class1');
oldElem.toggleClass('class1');
activeElem.prev().toggleClass('class1');
and the second part
2) I can not create a function which is working as a method. What I meant is how to change:
jQuery('#something').addClass('class1')
.removeClass('class2');
to something like this:
jQuery('#something').changeClasses();
function changeClasses(){
.addclass('class1');
.removeClass('class2');}
This one is still unsolved by me.
So I am trying to make a string out of a string and a passed variable(which is a number).
How do I do that?
I have something like this:
function AddBorder(id){
document.getElementById('horseThumb_'+id).className='hand positionLeft'
}
So how do I get that 'horseThumb' and an id into one string?
I tried all the various options, I also googled and besides learning that I can insert a variable in string like this getElementById("horseThumb_{$id}") <-- (didn't work for me, I don't know why) I found nothing useful. So any help would be very appreciated.
Your code is correct. Perhaps your problem is that you are not passing an ID to the AddBorder function, or that an element with that ID does not exist. Or you might be running your function before the element in question is accessible through the browser's DOM.
Since ECMAScript 2015, you can also use template literals (aka template strings):
document.getElementById(`horseThumb_${id}`).className = "hand positionLeft";
To identify the first case or determine the cause of the second case, add these as the first lines inside the function:
alert('ID number: ' + id);
alert('Return value of gEBI: ' + document.getElementById('horseThumb_' + id));
That will open pop-up windows each time the function is called, with the value of id and the return value of document.getElementById. If you get undefined for the ID number pop-up, you are not passing an argument to the function. If the ID does not exist, you would get your (incorrect?) ID number in the first pop-up but get null in the second.
The third case would happen if your web page looks like this, trying to run AddBorder while the page is still loading:
<head>
<title>My Web Page</title>
<script>
function AddBorder(id) {
...
}
AddBorder(42); // Won't work; the page hasn't completely loaded yet!
</script>
</head>
To fix this, put all the code that uses AddBorder inside an onload event handler:
// Can only have one of these per page
window.onload = function() {
...
AddBorder(42);
...
}
// Or can have any number of these on a page
function doWhatever() {
...
AddBorder(42);
...
}
if(window.addEventListener) window.addEventListener('load', doWhatever, false);
else window.attachEvent('onload', doWhatever);
In javascript the "+" operator is used to add numbers or to concatenate strings.
if one of the operands is a string "+" concatenates, and if it is only numbers it adds them.
example:
1+2+3 == 6
"1"+2+3 == "123"
This can happen because java script allows white spaces sometimes if a string is concatenated with a number. try removing the spaces and create a string and then pass it into getElementById.
example:
var str = 'horseThumb_'+id;
str = str.replace(/^\s+|\s+$/g,"");
function AddBorder(id){
document.getElementById(str).className='hand positionLeft'
}
It's just like you did. And I'll give you a small tip for these kind of silly things: just use the browser url box to try js syntax. for example, write this: javascript:alert("test"+5) and you have your answer.
The problem in your code is probably that this element does not exist in your document... maybe it's inside a form or something. You can test this too by writing in the url: javascript:alert(document.horseThumb_5) to check where your mistake is.
Another way to do it simpler using jquery.
sample:
function add(product_id){
// the code to add the product
//updating the div, here I just change the text inside the div.
//You can do anything with jquery, like change style, border etc.
$("#added_"+product_id).html('the product was added to list');
}
Where product_id is the javascript var and$("#added_"+product_id) is a div id concatenated with product_id, the var from function add.
Best Regards!