How to give last class to other element with jquery? - javascript

I have some list elements with dynamically id changing. Next i give this id's to other element, as a class one by one. So, this is my code:
$('#rounded_items li').one({click: function(){
$('#back_button').addClass(this.id);
}});
and #back_button receives classes 1, 2, 3, 4 from #rounded_items li. How can i grab the last class from back_button and give it to #rounded_items by click.
Is there any possible to give back the last class from element who receives this class?

maybe you can store it as data
$('#rounded_items li').one('click', function(){
var classes = $('#back_button').attr('class').split(/\s+/);
var last = classes[classes.length-1];
$.data($('#back_button')[0],'lastclass',last);
$('#back_button').addClass(this.id);
});
$('#back_button').click(function(){
var lastclass = $.data($('#back_button')[0],'lastclass');
$('#rounded_items').addClass(lastclass);
var classes = $('#back_button').attr('class').split(/\s+/);
$.data($('#back_button')[0],'lastclass',classes[classes.length-3]);
$('#back_button').removeClass(classes[classes.length-1]);
});
you can also try this:
$('#back_button').click(function(){
var classes = $('#back_button').attr('class').split(/\s+/);
$('#rounded_items').addClass(classes[classes.length-2]);
$('#back_button').removeClass(classes[classes.length-1]);
});

Use an array to store the ids, not a class attribute!
var stack = [];
$('#rounded_items li').one('click',function(){
stack.push(this.id);
});
$('#back_button').click(function(){
$('#rounded_items').setClass(stack.pop());
});

I'm assuming that your classes aren't really being used to style anything, as they're not legal CSS identifiers. If the intent is just to store some state, use .data:
var $back = $('#back_button');
$back.data('state', []); // empty array to store state
$('#rounded_items li').one({click: function() {
$back.data('state').push(this); // store clicked element
});
$back.on('click', function() {
var elem = $back.date('state').pop(); // retrieve last clicked element
if (elem) {
// do something with elem...
}
});
If the code is all in the same lexical scope you can just use a local array to store the state without using .data().

Related

Create a unique identifier for a DOM element

I am creating an object that stores various elements and their CSS properties.
The code I have now:
// My object
var cssStorage = {};
function store(element, cssProperty, value) {
// Initialize the (sub-)objects if they don't exist
cssStorage[element.id] = cssStorage[element] || {};
cssStorage[element.id][cssProperty] = cssStorage[element][cssProperty] || {};
// Set the cssProperty to equal the value
cssStorage[element.id][cssProperty] = value;
};
Example:
// My element
var box = document.getElementById("box");
// Let's call the function twice to save to properties
store(box, "display", "block");
store(box, "height", "74px");
Now my Object is populated like so:
cssStorage = {
box: { // <- box is the id of the HTML element <div id = "box"></div>
// The property-value pairs
display: "block",
height: "74px"
}
};
So now, if I type the code in the console:
return cssStorage.box.display; // Returns "block"
As you saw in the first block of code I posted, I used element.id as the element's unique identifier, to be able to use it as shown right above.
My problem is the dependency of my script upon element.id. Some elements of my DOM don't have an id and therefore the function is useless for these elements.
In essence, what I want to achieve is to call the function store when my element doesn't have an ID as follows:
// Some ways to get an element
var box = document.getElementsByClassName("boxes")[0];
var box = document.getElementsByTagName("div")[0];
var box = document.getElementsByName("jack")[0];
// It'll show an error, as the function uses 'element.id' and my element doesn't have one
store(box, "display", "block");
Is there a unique identifier for every node in the DOM?
Something that I could use as the name of:
cssStorage = {
[THE NAME]: {}
};
If not, how can I create a unique identifier for my elements, so that I can use the function as shown above without needing an id, class or other property that my element may not have?
You can easily coin a unique identifier for any element that doesn't yet have one:
var customIDprefix = "__myCustomPrefix__";
var customIDcntr = 0;
function getNextID() {
return customIDprefix + customIDCntr++;
}
And, then you can make sure any element you're using has a unique ID:
function checkID(elem) {
if (!elem.id) {
elem.id = getNextID();
}
}
If you're using ES6, you can also just use a WeakMap or Map object as your CSSStorage mechanism which let the DOM element itself be the key so you don't have to make a string key.
In that case, you'd just do this:
var cssStorage = new Map();
cssStorage[elem] = { // <- elem (your DOM element itself) becomes your key into the cssStorage
// The property-value pairs
display: "block",
height: "74px"
}
You could use an integer to handle a sequence and set the id to elements that does not have it, prefixing to avoid duplicates (for example 'myid' + idSequence++).
Please check if this works. Basically trying to clone the original element and assign it back to the original after adding id with random generator.
function store(element, cssProperty, value) {
if ( element.id == undefined ) {
var clonedElem = element.cloneNode(true);
clonedElem.id = Math.floor((Math.random() * 1000) + 1);
element = clonedElem;
}
// Initialize the (sub-)objects if they don't exist
cssStorage.[element.id] = cssStorage[element] || {};
cssStorage.[element.id][cssProperty] = cssStorage.[element][cssProperty] || {};
// Set the cssProperty to equal the value
cssStorage.[element.id][cssProperty] = value;
};

jQuery appendTo does not work under $.post

// plays a card into table.
// this code works. rendered card is appending into the table.
var playCard = function(card){
var renderedCard = renderCard(card);
$('#'+renderedCard.id).appendTo('#flop');
// but this one does not work.
var playCom = function(){
$.post('/api/comPlay', function(data){
var renderedCard = renderCard(data.card);
$('#'+renderedCard.id).appendTo('#flop');
});
};
I check the returned value from $.post. data.card gives the correct value. I create a div html with my renderCard function. That function works correctly as you see. But under $.post not.
I am stuck. Is there something special that i must know about $.post?
Thank you.
update :
var renderCard = function(card){
var create = document.createElement('div');
create.className = 'cardBig';
create.id = card;
return create;
};
You don't need to "find" your newly-created DOM element.
$(renderedCard).appendTo('#flop');
should do it.
Also, since you're using jQuery anyway:
$('#flop').append($('<div/>', {
className: 'cardBig',
id: data.card
}));
will save you the extra function.
In renderCard() method you are just creating a new html element but it is not rendered to the dom.
So your element lookup $('#'+renderedCard.id) will not work
$(renderedCard).appendTo('#flop');
have you tried selecting the id element first, like so:
$(renderedCard).appendTo( $('#flop')[0] )

jquery combine similar code

I have many jquery click function, they are very similar, how to combine them for shorter code. (use regex or use array foreach?)
$(".menu").live('click', function() {
var value = $(this).html();
$('#menu').html(value);
});
$(".nav").live('click', function() {
var value = $(this).html();
$('#nav').html(value);
});
$(".list").live('click', function() {
var value = $(this).html();
$('#list').html(value);
});
This should do:
var elems = ["menu", "nav", "list"];
$.each(elems, function(i, elem){
$("."+elem).live('click',function(){
var value = $(this).html();
$('#'+elem).html(value);
});
});
Create a list of elements.
Loop through it using $.each
The second argument of the function equals the element in the list (menu, nav, ..)
Rob's answer is definitely vote-up-worthy, but I just wanted to say that sometimes you want to limit the arbitrary connections between two elements. Why should element X have a class that MUST be the same name as element Y's ID? It's pretty arbitrary and can be a hassle for people to later figure out.
You can instead approach it like this to make it more robust:
alice
bob
sue
Now your JS becomes super straight-forward and easy:
$(".foo").live('click',function(){
var value = $(this).html();
var yourDataAttr= $(this).data('yourDataAttr');
$('#' + yourDataAttr).html(value);
});

Remove multiple elements with same name using removeChild?

I have an element with multiple elements inside. All of the elements inside have the same name. Is there any way to remove them using one function?
(refer to this question for example Remove multiple children from parent?
Here's a solution that removes the first level children with the specified name for the parent with the specified id. If you want to go deeper, you can recursively call it on the child elements you get inside (you'll have to add a parent parameter as well).
function removeChildren (params){
var parentId = params.parentId;
var childName = params.childName;
var childNodes = document.getElementById(parentId).childNodes;
for(var i=childNodes.length-1;i >= 0;i--){
var childNode = childNodes[i];
if(childNode.name == 'foo'){
childNode.parentNode.removeChild(childNode);
}
}
}
And to call it:
removeChildren({parentId:'div1',childName:'foo'});
And a fiddle for testing:
Notes: You can only access the name element dependably in JavaScript when it supported on your element (e.g. NOT on DIVs!). See here for why.
UPDATE:
Here's a solution using className based on our conversation:
function removeChildren (params){
var parentId = params.parentId;
var childName = params.childName;
var childNodesToRemove = document.getElementById(parentId).getElementsByClassName('foo');
for(var i=childNodesToRemove.length-1;i >= 0;i--){
var childNode = childNodesToRemove[i];
childNode.parentNode.removeChild(childNode);
}
}
2021 Answer:
Perhaps there are lots of way to do it, such as Element.replaceChildren().
I would like to show you an effective solution with only one redraw & reflow supporting all ES6+ browsers.
function removeChildren(cssSelector, parentNode){
var elements = parentNode.querySelectorAll(cssSelector);
let fragment = document.createDocumentFragment();
fragment.textContent=' ';
fragment.firstChild.replaceWith(...elements);
}
Usage: removeChildren('.foo',document.body);: remove all elements with className foo in <body>
ok this should be easy. First get the parent element:
var theParent = document.getElementById("notSoHappyFather");
then get an array of the nodes that you want to remove:
var theChildren = theParent.getElementsByName("unluckyChild");
Lastly, remove them with a loop:
for (var i = 0; i < theChildren.length; i++)
{
theParent.removeChild(theChildren[i]);
}
A sample of your HTML would get you a more complete answer, but one can fairly easy call DOM functions to get the list of children and just remove them. In jQuery, remove all children would be something like this:
$("#target > *").remove();
or
$("#target").html("");
And, you can see a demo here: http://jsfiddle.net/jfriend00/ZBYCh/
Or, not using jQuery you could also do:
document.getElementById("target").innerHTML = "";
If you're trying to only remove a subset of the children (and leave others intact), then you need to be more specific how one would determine which children to leave and which to remove. In jQuery, you could use a .find() select or a filter() selector to narrow the list of children to just the children you wanted to target for removal.

Looping over elements in jQuery

I want to loop over the elements of an HTML form, and store the values of the <input> fields in an object. The following code doesn't work, though:
function config() {
$("#frmMain").children().map(function() {
var child = $("this");
if (child.is(":checkbox"))
this[child.attr("name")] = child.attr("checked");
if (child.is(":radio, checked"))
this[child.attr("name")] = child.val();
if (child.is(":text"))
this[child.attr("name")] = child.val();
return null;
});
Neither does the following (inspired by jobscry's answer):
function config() {
$("#frmMain").children().each(function() {
var child = $("this");
alert(child.length);
if (child.is(":checkbox")) {
this[child.attr("name")] = child.attr("checked");
}
if (child.is(":radio, checked"))
this[child.attr("name")] = child.val();
if (child.is(":text"))
this[child.attr("name")] = child.val();
});
}
The alert always shows that child.length == 0. Manually selecting the elements works:
>>> $("#frmMain").children()
Object length=42
>>> $("#frmMain").children().filter(":checkbox")
Object length=3
Any hints on how to do the loop correctly?
don't think you need quotations on this:
var child = $("this");
try:
var child = $(this);
jQuery has an excellent function for looping through a set of elements: .each()
$('#formId').children().each(
function(){
//access to form element via $(this)
}
);
Depending on what you need each child for (if you're looking to post it somewhere via AJAX) you can just do...
$("#formID").serialize()
It creates a string for you with all of the values automatically.
As for looping through objects, you can also do this.
$.each($("input, select, textarea"), function(i,v) {
var theTag = v.tagName;
var theElement = $(v);
var theValue = theElement.val();
});
I have used the following before:
var my_form = $('#form-id');
var data = {};
$('input:not([type=checkbox]), input[type=checkbox]:selected, select, textarea', my_form).each(
function() {
var name = $(this).attr('name');
var val = $(this).val();
if (!data.hasOwnProperty(name)) {
data[name] = new Array;
}
data[name].push(val);
}
);
This is just written from memory, so might contain mistakes, but this should make an object called data that contains the values for all your inputs.
Note that you have to deal with checkboxes in a special way, to avoid getting the values of unchecked checkboxes. The same is probably true of radio inputs.
Also note using arrays for storing the values, as for one input name, you might have values from several inputs (checkboxes in particular).
if you want to use the each function, it should look like this:
$('#formId').children().each(
function(){
//access to form element via $(this)
}
);
Just switch out the closing curly bracket for a close paren. Thanks for pointing it out, jobscry, you saved me some time.
for me all these didn't work. What worked for me was something really simple:
$("#formID input[type=text]").each(function() {
alert($(this).val());
});
This is the simplest way to loop through a form accessing only the form elements. Inside the each function you can check and build whatever you want. When building objects note that you will want to declare it outside of the each function.
EDIT
JSFIDDLE
The below will work
$('form[name=formName]').find('input, textarea, select').each(function() {
alert($(this).attr('name'));
});

Categories