PrototypeJS loop won't run - javascript

I have a loop which won't run using Prototype + Scriptaculous. It runs once for the first object in my array then stops.
var myMessages = new Object();
myMessages = ['success','info','warning','error']; // define the messages types
function hideAllMessages()
{
var messagesHeights = new Array(); // this array will store height for each
enter code here
// This one runs just once for the first item in the array
var i = 0;
myMessages.each(function(element) {
alert(element);
messagesHeights[i] = $('.' + element).getHeight();
i++;
$$('.' + element + ' message').invoke('hide');
});
//This won't run at all===============================
for (var index = 0; index < myMessages.length; index++)
{
messagesHeights[index] = $('.' + myMessages[index]).getHeight();
$('x').hide();
//$('.' + myMessages[i]).css('top', -messagesHeights[i]); //move element outside viewport
}
}

I'm not a prototype user, but here's what I see so far:
$ is for IDs. I believe you need $$ here:
$$('.' + element)
This returns an Array, so I think you need invoke() like this:
$$('.' + element).invoke('getHeight');
Also, .each() passes the index as the second argument to the callback, so you don't need to maintain your own i.
myMessages.each(function(element, i) {
Also, this:
$$('.' + element + ' message')
...would seem to be looking for elements with the tag named message. I assume you want a class instead.
$$('.' + element + ' .message').invoke('hide');

Related

Element undefined in jQuery each iteration

I'm trying to iterate over a collection of jQuery elements as follows:
var l = $(".ace_line").length;
$(".ace_line").each($(function(index,element) {
console.log("Element = " + element);
console.log(index + ": " + element.text());
}));
When I examine l its value is 39 so I know the collection is not null.
However element is undefined when I loop through the collection.
What am I doing wrong?
Any help would be appreciated!
A couple of problems there:
You're wrapping your callback in $(), which makes jQuery think you're using the shorthand version of $(document).ready(function...). Since the DOM is ready, it calls that function (once) passing it the jQuery instance as the first argument and no second argument at all.
You're not using $() around element. element will just be a DOM element, not a jQuery instance, so to call text on it, you need to wrap it first.
So:
var l = $(".ace_line").length;
$(".ace_line").each(function(index,element) {
// No $( here ------^
var $el = $(element); // <=== Do wrap `element`
console.log("Element = " + $el);
console.log(index + ": " + $el.text()); // <=== Use $el
}); // <== Removed a ) here
Note that the more normal thing to do would be to use this:
var l = $(".ace_line").length;
$(".ace_line").each(function(index) {
var $el = $(this); // <===
console.log("Element = " + $el);
console.log(index + ": " + $el.text()); // <===
});
Remove the $( from within the each function, like so:
var l = $(".ace_line").length;
$(".ace_line").each(function(index,element) {
console.log("Element = " + element);
console.log(index + ": " + $(element).text());
});
Additionally, your element will be a HTML DOM element, not a jQuery item, so to get .text() you would need $(element).text()
you are using wrong syntax $(function(){})
caching variables makes your script is faster
for is faster than each()
by using for you do not have to wrap your element with $() again
jQuery
var lines = $(".ace_line"); //caching the element
var l = lines.length; //getting length for loop without selecting element again
for (var j = 0; j < l; j++){ //for loop where j is your index
console.log(lines.eq(j)); //getting the element by using jQuery's eq()
console.log(lines.eq(j).text()); //use any jQuery function on the element
}

how to delete specific value from array jquery

Hello I can't find out how to delete a specific value from string when clicking on an element with the string value. its for my todo list.
if (window.localStorage.fullName !== undefined) {
alert('Your browser does not support localStorage');
} else {
$(function () {
console.log('localSorage compitability detected. proceeding...');
global vars & functions
var tdli = [];
add list items
$('#tdladd').click(function () {
$('.todolist ul ul').append("<li class='tdli'>" + $('#tdlinput').val() + "</li>");
tdli.push($('#tdlinput').val());
$('#tdlinput').val('');
var array = tdli + "";
localStorage.setItem('tdlis', array);
console.log(array);
$('#todolist').hide().fadeIn('fast');
});
remove list items
$('li').click(function () {
var itemtoRemove = $(this);
tdli.splice($.inArray(itemtoRemove, tdli), 1);
console.log(tdli);
});
$('#clearall').click(function () {
localStorage.clear();
location.reload();
});
load list items
var tdlitems = localStorage.getItem('tdlis');
var array = tdlitems.split(',');
tdli.push(array);
for (var i = 0; i < array.length; i++) {
array[i] + "<br>";
$('.todolist ul ul').append("<li>" + array[i] + "</li>");
};
console.log(array);
});
}
Assuming that tdli is a jQuery wrapped set (which itself is an array-like-object), it will have DOM nodes stored instead of another jQuery objects. That means, just go like
var itemtoRemove = this;
and you should be fine.
After you posted your complete code, we can see you're actually pushing string values into your tdli Array, but you try to .splice() objects respectively DOM nodes, which of course doesn't make any sense at all (comparing apples to oranges).

iterate over array in jquery

I'm trying to do some validation on a user selecting items from a list. I want to make sure an item is not added twice by checking if the <li> is already in the array. This is what I'm trying and its not working.
$(".List").on("click", "li", function () {
var i = 0;
var checkArr = [];
var div = $("#AddedItems");
var parent = $(this).closest("ul");
var itemtoadd = parent.find("[data-id]").attr("data-id");
var name = parent.find("[data-name]").attr("data-name");
alert(itemtoadd + name);//checking
var itemtoadd = ("<li id = " + itemtoadd + " class = \"itemAdd\">" + name + "</li>");
checkArr.push(itemtoadd); //put one in to check against?
checkArr.forEach(item)
{
if (item == itemtoadd)
alert("this item has already been added");
else {
checkArr.push(itemtoadd);
alert(itemtoadd);
$(itemtoadd).appendTo(div);
}
}
// div.html(itemtoadd);
});
You have at least three problems here:
You aren't using Array.forEach correctly -- it takes a function that takes an item.
Immediately before you do your check, you're adding the item you're looking for. You will always hit the alert case.
You're using checkArr as a local variable -- you're getting an empty array each time you enter the function.
That all being said, you can accomplish your goal without keeping an array at all. I believe you can replace everything from your first alert down with this:
if ($('#' + itemtoadd, div).length == 0) {
itemtoadd = ("<li id = " + itemtoadd + " class = \"itemAdd\">" + name + "</li>");
div.append(itemtoadd);
}
else {
alert("this item has already been added");
}

Use "event's" output as a variable

I have a problem to manipulate checkbox values. The ‘change’ event on checkboxes returns an object, in my case:
{"val1":"member","val2":"book","val3":"journal","val4":"new_member","val5":"cds"}
The above object needed to be transformed in order the search engine to consume it like:
{ member,book,journal,new_member,cds}
I have done that with the below code block:
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr=[];
for (var i in value) {
arr.push(value[i])
};
var wrd = new Array(arr);
var joinwrd = wrd.join(",");
var filter = '{' + joinwrd + '}';
//console.log(filter);
//Ext.Msg.alert('Output', '{' + joinwrd + '}');
});
The problem is that I want to the “change” event’s output (“var filter” that is producing the: { member,book,journal,new_member,cds}) to use it elsewhere. I tried to make the whole event a variable (var output = “the change event”) but it doesn’t work.
Maybe it is a silly question but I am a newbie and I need a little help.
Thank you in advance,
Tom
Just pass filter to the function that will use it. You'd have to call it from inside the change handler anyway if you wanted something to happen:
formcheckbox.on('change', function(cb, value){
//...
var filter = "{" + arr.join(",") + "}";
useFilter(filter);
});
function useFilter(filter){
// use the `filter` var here
}
You could make filter a global variable and use it where ever you need it.
// global variable for the search filter
var filter = null;
var formcheckbox = this.getFormcheckbox();
formcheckbox.on('change', function(checkbox, value){
var arr = [],
i,
max;
// the order of the keys isn't guaranteed to be the same in a for(... in ...) loop
// if the order matters (as it looks like) better get them one by one by there names
for (i = 0, max = 5; i <= max; i++) {
arr.push(value["val" + i]);
}
// save the value in a global variable
filter = "{" + arr.join(",") + "}";
console.log(filter);
});

How to change the id of deep nested elements with jQuery

I have this recursive code that transverses the DOM and adds a prefix to the id for all input tags.
I would like to change this to a more elegant jQuery, but I'm not sure how to structure the selectors or if the selectors need to be recursive..
cheers,
function set_inputs(obj, prefix){
for (var s=0;s< obj.childNodes.length; s++){
var node = obj.childNodes[s];
if(node.tagName == "INPUT"){
node.id= prefix +'_' + node.id;
node.name= prefix +'_' + node.name;
}
else{
set_inputs(node,prefix);
}
}
}
For the entire DOM.
It would be as simple as:
var prefix;
$("input").each(function(i,elem)
{
$(elem).attr("id", prefix + "_" + $(elem).attr("id"));
});
You could change the selector : $("input") - which selects all the doms inputs, to any other selector to target different elements.
If you wanted it separately in a function then:
function() set_inputs(col, prefix) {
col.each(function(i,elem)
{
$(elem).attr("id", prefix + "_" + $(elem).attr("id"));
});
}
You would then use it like this:
set_inputs($("input"), "abc");//prefix ALL the DOM's inputs with abc
set_inputs($("input.btn"), "abc");//prefix inputs with the css-class btn
No particular need to use jQuery for this either. It could be done in plain javascript without recursion using getElementsByTagName() like this:
function set_inputs(obj, prefix) {
var nodes = obj.getElementsByTagName("input");
for (var i = 0, len = nodes.length; i < len; i++) {
if (nodes[i].id) {
nodes[i].id = prefix + '_' + nodes[i].id;
}
if (nodes[i].name) {
nodes[i].name = prefix + '_' + nodes[i].name;
}
}
}
P.S. I added protection in the code that your code did not have in case input tags exist without an id or a name attribute so the code won't error out if it encounters that. If you didn't want that protection, the code would be shorter like this:
function set_inputs(obj, prefix) {
var nodes = obj.getElementsByTagName("input");
for (var i = 0, len = nodes.length; i < len; i++) {
nodes[i].id = prefix + '_' + nodes[i].id;
nodes[i].name = prefix + '_' + nodes[i].name;
}
}
You call this function by passing it two arguments, the DOM object that represents the top of the part of the DOM tree you want to search for input tags in and the prefix you want to add to the IDs. If you do something like this: set_inputs(document.body, "test") it will search the entire document. If you do something like this: set_inputs(document.getElementById("top"), "test"), it will only search a portion of the DOM tree (the part under the id=top element). You can pass it any arbitrary DOM object and it will only search the nodes in that hierarchy.
Just want to suggest a small change
$('input').each(function(){
this.id = prefix + this.id;
});
To pull the deep nested inputs, use jquery find(). This solution is much simpler code than recursive javascript. I did leave out the steps verifying the existence of id and name attributes which should be done for production code.
$(obj).find("input").each(function(){
$(this).attr('id',prefix + "_" + $(this).attr('id'));
$(this).attr('name',prefix + "_" + $(this).attr('name'));
});

Categories