add options to select - multiple selects - javascript

I have 4 selects and I want to append the options to all 4 selects using their class.
// groupings is just an array of strings
createElement: function(el, value, html) {
var htmlText = html || value;
var elm = document.createElement(el);
elm.value = value;
elm.innerHTML = htmlText;
return elm;
}
var htmlOptions = [];
$.each(groupings, function(i, e) {
htmlOptions.push(_util.createElement("option", e));
});
$('.groupBy_impact').append(htmlOptions);
This seems to work in Chrome, but in IE and Firefox, the values are overflown outside the select box. Not sure why.
If I do the following then it works cross-browser, but I want to avoid it
$('#select_groupBy_impact_1').append(htmlOptions);
$('#select_groupBy_impact_2').append($(htmlOptions).clone());
$('#select_groupBy_impact_3').append($(htmlOptions).clone());
$('#select_groupBy_impact_4').append($(htmlOptions).clone());

Something like this should work, if you want to avoid cloning.
$('.groupBy_impact').each(function() {
$(thid).append(htmlOptions);
});
This avoids cloning and iterates through all the elements in the collection.
It is important that all the elements you need to use this on, have the groupBy_impact class.
Furthermore .append() can take in different parameters.
You are using jQuery, why not make your .createElement(); return jQuery objects that are put into an array. this will be easier for jQuery to handle.
Or even better. Create a new jQuery collection (instead of an array) and append the created jQuery objects to that empty jQuery object, essentially creating a new collection of DOM elements to add.

try something like this
var htmlOptions_len = htmlOptions.length;
for(var i= 0;i<htmlOptions_len;i++ ){
$('.groupBy_impact').append(htmlOptions[i]);
}
or simply try something like this
$.each(groupings, function(i, e) {
$('.groupBy_impact').append(_util.createElement("option", e));
});

Related

How to sum elements dynamically added with Javascript?

I am adding table rows dynamically to a table using Javascript.
Is there a reason why items.length doesn't increase when I add a row?
I am also trying to sum the numbers contained in each row. But this doesn't work either. The dynamically added rows are completely ignored for some reason.
I am coming from jQuery where things like these used to work.
I am probably missing something really fundamental here. Thanks for any pointers.
document.addEventListener("DOMContentLoaded", function() {
var form = document.querySelector("#form");
var items = form.querySelectorAll(".item");
form.addEventListener("click", function(event) {
if (event.target.className == ".add_item") {
addFields(event);
}
});
function addFields(event) {
var item = document.createElement("template");
item.innerHTML = fields.trim();
items[items.length - 1].insertAdjacentElement("afterend", item.content.firstChild);
console.log(items.length);
event.preventDefault();
}
})
querySelector and querySelectorAll returns NodeList where as getElementsByClassName returns HTMLCollection.
The difference is, NodeList is a static copy but HTMLCollection is a live copy. So if element is modified, like in your case, a new row is added, HTMLCollection will work but NodeList will not.
So changing
var items = form.querySelectorAll(".item")
to
var items = form.getElementsByClassName("item")
might solve the problem.
Pointers
You cannot have a selector in getElementsByClassName. It expects a className, you cannot use composite selector like #form .item.
Reference:
Difference between HTMLCollection, NodeLists, and arrays of objects
You only query the items once here:
var items = form.querySelectorAll(".item");
form.addEventListener(
//you call addItem here
)
function addItem(){
//you access items.length here
}
You need to keep re-query-ing the selectors every time you add an item.
var items = form.querySelectorAll(".item"); //i got queried for the 1st time
function addFields(event) {
items = form.querySelectorAll(".item"); //get items again
//...
}
Or just don't query outside addFields() all in all. Put var items = ... in the function. There's no need to put it outside.
Read up #Rajesh's answer why this is so.

Generating a comma delimited string, from select element in jQuery

Here's what's going on. I have a select element, for which I need to get a comma delimited string of all its options, regardless of whether or not it's selected.
How can I, in jQuery/javascript take this:
<select id="currentTags" multiple>
<option>Nature</option>
<option>Cats</option>
<option>Space</option>
</select>
and turn it into this:
"Nature, Cats, Space"
I tried to find ways of doing this and couldn't... I'm still learning javascript, and my limited knowledge is stopping me in my tracks.
Any help would be appreciated, even if it's just to guide me in the right direction.
Thank you for your time.
With jQuery:
var result = $('#currentTags option').map(function(i, opt) {
return $(opt).text();
}).toArray().join(', ');
In plain JavaScript you can do something similar like this:
// Convert pseudo-arrays to real arrays
var __slice = Array.prototype.slice;
// Get select options as real array
var opts = __slice.call(document.querySelectorAll('#currentTags option'));
// Map the text of each option
var result = opts.map(function(x) {
return x.textContent;
}).join(', ');
console.log(result); //=> "Nature, Cats, Space"
The advantage of abstracting elements into collections instead of looping is that you maintain a consistent API (like jQuery), and you don't need to create extra variables to loop pseudo-arrays, as real arrays can use all array methods.
See the MDN to learn more about the DOM and the methods and properties you can use, like querySelectorAll, children, textContent and more.
Edit: This should work in IE9+ and all modern browsers.
The plain old javascript (POJS) way is to get the select's options collection, then loop over it to get the values and generate a string with the required format, e.g.
var options = document.getElementById('currentTags').options;
var values = [];
for (var i=0, iLen=options.length; i<iLen; i++) {
values.push(options[i].text);
}
alert(values.join(','));
You can write that in much more concise form but performance may suffer and depending on features used, may fail in some browsers. The above puts a premium on clarity and maintainability of code, performance will be at least as fast as any alternative.
How about just:
var tags = [];
$('#currentTags option').each(function() {
tags.push($(this).val());
});
console.log(tags.join(', ')); // 'Nature, Cats, Space'
http://jsfiddle.net/wN2Dk/
Here is a simple jQuery example:
var arr = []; // create array
$('#currentTags').children().each(function() {
arr.push($(this).text()); // add option text to array
});
alert(arr.join(', ')); // Nature, Cats, Space
If you want the option value, switch text() to val() ;)
A simple solution would be:
// Initialize your string
var output_string = "";
// For each 'option' tag, append its value to the string with the comma
$('#currentTags option').each(function() {
output_string = output_string+this.text;
});
// Removing the last ', ' which were added during the loop
output_string = output_string.substr(0, output_string.length-2);
Here's a Fiddle to see it into action :)

How can I select elements on dom (with jQuery) that has some data attribute that ends with "created"?

I have all my elements, on a project, that are being transferred with data attributes so the javascript can know what to do.
But I have one problem, one part of the application must get all the created variables to compare time, and I have they saved like (data-product-created, data-category-created, data-link-created, etc...). It would be a huge headache if I had to put them manually on the jQuery selector...
Do jQuery has some method to search custom data attributes existence?
Like: element[data-(.*)-created]
You could create a low level Javascript method to loop through elements and pull their created values:
var getCreateds = function($els) {
var returnSet = [];
$els.each(function(i, el){
var elDict = {'el': el};
$.each(el.attributes, function(i, attr){
var m = attr.name.match(/data\-(.*?)\-created/);
if (m) elDict[m[1]] = attr.value;
});
returnSet.push(elDict);
});
return returnSet;
};
See demo
Based on mVChr answer (THANK YOU), i've rewritten the code on a simple, better and clean code:
jQuery('div').filter(function(){
for( var i in this.attributes ){
if(typeof this.attributes[i] !== 'object') continue;
if(this.attributes[i].name.match(/data\-(.*?)\-created/)) return true;
}
return false;
})
Changes:
+ Verifying attribute type... some attributes are browser internal functions or callbacks.
~ Using filter handler from jQuery, its better and cleaner way.
~ Using for instead of $.each, faster indeed.

jQuery append() for multiple elements after for loop without flattening to HTML

I have a loop:
for (index = 0; index < total_groups; index += 1) {
groups[index].list_item = $(list_item_snippet);
// Closure to bind the index for event handling
(function (new_index) {
groups[index].list_item.find('.listing-group-title')
.html(groups[index].Group.Name)
.click(function(e){
fns.manageActiveGroup(new_index, groups);
return false;
});
})(index);
// Append to DOM
mkp.$group_listing.append(groups[index].list_item);
};
I would rather not call append() each time the loop fires.
I know that I could use a String and concatenate the markup with each loop iteration and append the string to mkp.$group_listing at the end, however this flattens the object and the bindings are lost (I am not relying on IDs).
Is there a way to perhaps add my objects to an array and append them all in one go at the bottom without flatening to HTML?
Assumptions:
$(list_item_snippet) contains some HTML defining a list item (and includes an element with class .listing-group-title).
groups is a block of JSON defining a 'group' in my script
The closure works perfectly
Edit:
Found that I can use the following syntax to append multiple elements:
mkp.$group_listing.append(groups[0].list_item, groups[1].list_item );
But i obviously need to automate it - it's not an array it's just optional additional function parameters so I'm not sure how to do this.
To append an array of elements to a selector you can use this:
$.fn.append.apply($sel, myArray);
In your case, since it's actually the .list_item property of each array element that you need you can use $.map to extract those first:
$.fn.append.apply(mkp.$group_listing, $.map(groups, function(value) {
return value.list_item;
}));
Instead of bind it the way you've done, if you bind it using on() like below,
$(document).on('click', '.listing-group-title', function() {
// click handler code here
});
You can flatten the HTML and append it in one statement and it'll still work.
Note: For better efficiency, replace document in the above statement to a selector matching the closest parent of .listing-group-title
Yes. Use the jQuery add method to add all your items to a jQuery object. Then append that one object.
http://api.jquery.com/add/
EDIT: Example:
var arr = $();
for (index = 0; index < total_groups; index += 1) {
groups[index].list_item = $(list_item_snippet);
// Closure to bind the index for event handling
(function (new_index) {
...
})(index);
// Add to jQuery object.
arr.add(groups[index].list_item));
};
mkp.$group_listing.append(arr);

find and replace text , word translation

I have some problems with finding and replacing words in PHP files, especially when there is tons of them. So I thought that I will try to use javascript / jQuery.
I'd like to create table witch word_to_replace#new_word to do so.
This is my code which doesn't work (and runs very long), filter doesn't seem to work,
any advices?
(function($){
var arr = [ 'photo-board.pl przyjazny portal fotograficzny# ','Upload images from your#Upload zdjęć z ',
'Total number of images# Całkowita liczba zdjęć'];
for(var i in arr)
{
var st_to_replace = arr[i].split('#')[0];
// alert(st_to_replace);
$('*').filter(function() {
return $(this).text() == st_to_replace;
}).html(arr[i].split('#')[1]);
}
}) (jQuery)
You're getting the text() of every page element (which will include the text of child elements) and replacing within it. That means, when you get the 'body' element you replace all the text, and then you get all the elements within body, and replace all the text, etc.
Something like this may work better:
(function($){
var arr = [ 'photo-board.pl przyjazny portal fotograficzny# ','Upload images from your#Upload zdjęć z ',
'Total number of images# Całkowita liczba zdjęć'];
var bodyText = $('body').html();
$.each(arr, function(i, v) {
var words = v.split('#');
var fromTxt = words[0], toTxt = words[1];
bodyText = bodyText.replace(fromTxt, toTxt);
});
$('body').html(bodyText);
})(jQuery);
Demo here.
It's worth noting though that since this destroys and recreates the entire body content, you'll loose event handlers and data set using .data(...).
One of the performance issues of your script is the immediate call to .html every iteration of the filter. This is causing the browser to repaint the element every iteration.
You might consider editing the html detached from the dom and then, after the for and the filter loops, replacing the html in the dom.

Categories

Resources