I can get div elements by id and using only partial name "first"
html
<div id="first.1.end">first.1.end</div>
<div id="first.2.end">first.2.end</div>
<div id="two.3.end">two.3.end</div>
<div id="first.4.end">first.4.end</div>
js
function getElementsByIdStartsWith(selectorTag, prefix) {
var items = [];
var myPosts = document.getElementsByTagName(selectorTag);
for (var i = 0; i < myPosts.length; i++) {
if (myPosts[i].id.lastIndexOf(prefix, 0) === 0) {
items.push(myPosts[i]);
}
}
return items;
}
var postedOnes = getElementsByIdStartsWith("div", "first");
alert(postedOnes.length);
It counts 3 div elements (alert).
But how can I use end-partial name for search? For example using "end"?
From MDN Attribute selectors:
[attr^=value] Represents an element with an attribute name of attr and
whose value is prefixed by "value".
[attr$=value] Represents an element with an attribute name of attr and
whose value is suffixed by "value".
So you can use [id^="first"] to find elements with id start with "first". and use [id$="end"] to find elements end with "end".
Like
// This find all div which id ends with "end".
var divs = document.querySelectorAll('div[id$="end"]');
or use jQuery:
$('div[id$="end"]');
Also, you can combine multiple attribute selectors altogether to find a more specific element:
// As we only use querySelector, it find the first div with id starts with "two" and ends with "end".
var divStartAndEnd = document.querySelector('div[id^="two"][id$="end"]');
See demo on jsfiddle
Here I am allowing user to pass all three parameters.
suppose user doesn't pass midmatch so it will return only match of first and last.
Below is the working code:
It will return 1 count:
function getElementsByIdStartsWith(selectorTag, firstmatch, midmatch, lastmatch) {
var items = [];
var myPosts = document.getElementsByTagName(selectorTag);
for (var i = 0; i < myPosts.length; i++) {
var firstmatchIndex = firstmatch?myPosts[i].id.indexOf(firstmatch)>-1?true : false : true;
var midmatchIndex = midmatch?myPosts[i].id.indexOf(midmatch)>-1?true : false : true;
var lastmatchIndex = lastmatch?myPosts[i].id.indexOf(lastmatch)>-1?true : false : true;
if (firstmatchIndex && midmatchIndex && lastmatchIndex ) {
items.push(myPosts[i]);
}
}
return items;
}
var postedOnes = getElementsByIdStartsWith("div", "first", "2", "end");
alert(postedOnes.length); // now it will show only one in alert.
It will return 3 count:
function getElementsByIdStartsWith(selectorTag, firstmatch, midmatch, lastmatch) {
var items = [];
var myPosts = document.getElementsByTagName(selectorTag);
for (var i = 0; i < myPosts.length; i++) {
var firstmatchIndex = firstmatch?myPosts[i].id.indexOf(firstmatch)>-1?true : false : true;
var midmatchIndex = midmatch?myPosts[i].id.indexOf(midmatch)>-1?true : false : true;
var lastmatchIndex = lastmatch?myPosts[i].id.indexOf(lastmatch)>-1?true : false : true;
if (firstmatchIndex && midmatchIndex && lastmatchIndex ) {
items.push(myPosts[i]);
}
}
return items;
}
var postedOnes = getElementsByIdStartsWith("div", "first", "", "end");
alert(postedOnes.length); // now it will show only three in alert.
if you don't want to consider any parameter just pass empty string( "" ) while calling the function.
Hope this will help you :)
I guess this kind of selection can be possible by using jQuery + regex. Have a look to this
How can I select an element by ID with jQuery using regex?
Might be some what on the line that you want.
Related
I am doing the below to get certain nodes from a treeview followed by getting text from those nodes, filtering text to remove unique and then appending custom image to the duplicate nodes.
For this I am having to loop 4 times. Is there is a simpler way of doing this? I am worried about it's performance for large amount of data.
//Append duplicate item nodes with custom icon
function addRemoveForDuplicateItems() {
var treeView = $('#MyTree').data('t-TreeView li.t-item');
var myNodes = $("span.my-node", treeView);
var myNames = [];
$(myNodes).each(function () {
myNames.push($(this).text());
});
var duplicateItems = getDuplicateItems(myNames);
$(myNodes).each(function () {
if (duplicateItems.indexOf($(this).text()) > -1) {
$(this).parent().append(("<span class='remove'></span>"));
}
});
}
//Get all duplicate items removing unique ones
//Input [1,2,3,3,2,2,4,5,6,7,7,7,7] output [2,3,3,2,2,7,7,7,7]
function getDuplicateItems(myNames) {
var duplicateItems = [], itemOccurance = {};
for (var i = 0; i < myNames.length; i++) {
var dept = myNames[i];
itemOccurance[dept] = itemOccurance[dept] >= 1 ? itemOccurance[dept] + 1 : 1;
}
for (var item in itemOccurance) {
if (itemOccurance[item] > 1)
duplicateItems.push(item);
}
return duplicateItems;
}
If I understand correctly, the whole point here is simply to mark duplicates, right? You ought to be able to do this in two simpler passes:
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node
myNodes.each(function () {
var name = $(this).text();
if (seen[name] === SEEN_DUPE) {
$(this).parent().append("<span class='remove'></span>");
}
});
If you're actually concerned about performance, note that iterating over DOM elements is much more of a performance concern than iterating over an in-memory array. The $(myNodes).each(...) calls are likely significantly more expensive than iteration over a comparable array of the same length. You can gain some efficiencies from this, by running the second pass over an array and only accessing DOM nodes as necessary:
var names = [];
var seen = {};
var SEEN_ONCE = 1;
var SEEN_DUPE = 2;
// First pass, build object
myNodes.each(function () {
var name = $(this).text();
var seen = seen[name];
names.push(name);
seen[name] = seen ? SEEN_DUPE : SEEN_ONCE;
});
// Second pass, append node only for dupes
names.forEach(function(name, index) {
if (seen[name] === SEEN_DUPE) {
myNodes.eq(index).parent()
.append("<span class='remove'></span>");
}
});
The approach of this code is to go through the list, using the property name to indicate whether the value is in the array. After execution, itemOccurance will have a list of all the names, no duplicates.
var i, dept, itemOccurance = {};
for (i = 0; i < myNames.length; i++) {
dept = myNames[i];
if (typeof itemOccurance[dept] == undefined) {
itemOccurance[dept] = true;
}
}
If you must keep getDuplicateItems() as a separate, generic function, then the first loop (from myNodes to myNames) and last loop (iterate myNodes again to add the span) would be unavoidable. But I am curious. According to your code, duplicateItems can just be a set! This would help simplify the 2 loops inside getDuplicateItems(). #user2182349's answer just needs one modification: add a return, e.g. return Object.keys(itemOccurance).
If you're only concerned with ascertaining duplication and not particularly concerned about the exact number of occurrences then you could consider refactoring your getDuplicateItems() function like so:
function getDuplicateItems(myNames) {
var duplicateItems = [], clonedArray = myNames.concat(), i, dept;
for(i=0;i<clonedArray.length;i+=1){
dept = clonedArray[i];
if(clonedArray.indexOf(dept) !== clonedArray.lastIndexOf(dept)){
if(duplicateItems.indexOf(dept) === -1){
duplicateItems.push(dept);
}
/* Remove duplicate found by lastIndexOf, since we've already established that it's a duplicate */
clonedArray.splice(clonedArray.lastIndexOf(dept), 1);
}
}
return duplicateItems;
}
//get email from test area
var emailList = document.getElementById("emailTextarea").value;
var emailListArray = emailList.split("\n");
//Remove yahoo and duplicates from the list
var usernamesArray = emailListArray.map(function(val, index, arr) {
return val.slice(0, val.indexOf('yahoo.com'));
});
Assuming:
emailListArray = ['123#gmail.com','123#yahoo.com','123#gmail.com','123#hotmail.com']
You can do something like this:
var usernamesArray = [];
emailListArray.forEach(function(item) {
if(usernamesArray.indexOf(item) < 0 && item.indexOf('yahoo.com') < 0) {
usernamesArray.push(item);
}
});
First condition checks if the element in turn is not already in the array of results, second condition checks if the element doesn't contain the substring yahoo.com, if both are true, the element is added to the results.
After that, usernamesArray should have:
[ '123#gmail.com', '123#hotmail.com' ]
i need to retrieve a value from an URL in JS, my problem is in this url, the element is repeated at least twice with different value. What i need is the last one.
Example :
http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3
and what i want is "random3" and NOT "random1"
I've tried url.match(/.(\&|\?)element1=(.?)\&/)[2];
But it always gives me the first one :(
I don't have the possibility to change how the url is written as this is for a browser extension.
var ws = "http://randomsite.com/index.php?element1=random1&element2=random2&element1=random3",
input = ws.split("?")[1].split("&"),
dataset = {},
val_to_find = "element1";
for ( var item in input){
var d = input[item].split("=");
if (!dataset[d[0]]){ dataset[d[0]] = new Array(); dataset[d[0]].push(d[1]); }
else{
dataset[d[0]].push(d[1]);
}
}
console.log("item: ", dataset[val_to_find][dataset[val_to_find].length -1]);
return dataset[val_to_find][dataset[val_to_find].length -1];
http://jsfiddle.net/wMuHW/
Take the minimum value (other than -1) from urlString.lastIndexOf("&element1=") and urlString.lastIndexOf("?element1="), then use urlString.substring.
Or alternately, split the string up:
var parts = urlString.split(/[?&]/);
...which will give you:
[
"http://randomsite.com/index.php",
"element1=random1",
"element2=random2",
"element1=random3"
]
...then start looping from the end of the array finding the first entry that starts with element= and grabbing the bit after the = (again with substring).
You could;
for (var result, match, re = /[&?]element1=(.+?)(\&|$)/g; match = re.exec(url);) {
result = match[1];
}
alert(result);
Id try keeping a nested array of duplicate elements
function parseQueryString() {
var elements = {},
query = window.location.search.substring(1),
vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('='),
key = decodeURIComponent(pair[0]),
value = decodeURIComponent(pair[1]);
if (elements.hasOwnProperty(key)) {
elements[key].push(value);
}
else {
elements[key] = [value];
}
}
}
Used on: www.example.com?element1=hello&element2=test&element1=more
Would give you the object:
{
element1: [
"hello",
"more"
],
element2:[
"test"
]
}
I am using a series of check boxes all are with different name that is checkbox1....checkbox40. I am generating a series of sting with '1' and '0' that is if check box is checked than sting will be concatenated with '1' else it will be concatenated with '0'. I have successfully implemented idea for PHP but as now I am using Ajax I want to develop same code for java script. My PHP code for that is
if (isset($_POST[submit]))
{
for ($i=1; $i<41; $i++)
{
$walue = "restriction".$i;
if(isset($_POST[$walue])) {$val .="1";} else {$val .="0";}
}
}
echo "Equivalent String: ".$val."<p>";
for implementing it using Javascript I have called a function on submit event of form.
My form id is theForm and my checkboxes name is restriction1....restriction40. Please give me hint to implement the idea.
So.. something like this?
getCheckedString = function () {
var chunks = [];
var checkboxes = $("#theForm").children('input[type=checkbox]').each(function () {
chunks[chunks.length] = $(this).is(':checked') ? '1' : '0';
});
return chunks.join('');
}
This will gather up all of the checkboxes in the order they are on the form, put a '1' or '0' in the array, then return the array joined into a string. It's not specific to a particular name, so if there are other checkboxes in the form let me know and I'll alter my answer.
If you have only named checkboxes, you would do:
function getCheckedString1() {
var val = "";
for (var i = 1; i <= 40; ++i) {
var boxes = document.getElementsByName("restriction" + i); // returns an array
if (boxes[0]) {
val += boxes[0].checked ? "1" : "0";
}
}
// alert(val);
return val;
}
However, it is easier and the usual praxis to identify the referenced HTML elements with ID's. So, you would enhance your HTML:
<input type="checkbox" name="restriction1" id="restriction1" ...
<input type="checkbox" name="restriction2" id="restriction2" ...
and then use:
function getCheckedString2() {
var val = "";
for (var i = 1; i <= 40; ++i) {
var box = document.getElementById("restriction" + i); // returns the unique element
if (box) {
val += box.checked ? "1" : "0";
}
}
// alert(val);
return val;
}
So, I am trying to make a "tabs menu", like this: http://flowplayer.org/tools/tabs/index.html
(but i dont want to use this.)
So, I tried to use url variables to set the active menu item.
Code:
onload=function(){
//Check if editPage is set
if (gup("editPage")) {
gupname = gup("editPage");
var x = "contentEditListItem"+gupname;
var y = document.getElementsByClassName(x);
y.className = "contentEditListItemActive";
}
}
function gup( name )
{
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
var regexS = "[\\?&]"+name+"=([^&#]*)";
var regex = new RegExp( regexS );
var results = regex.exec( window.location.href );
if( results == null )
return "";
else
return results[1];
}
The gup function works well, I get the wanted classname ("contentEditListItem"+gupname).
Why it is staying unchanged?
getElementsByClassName returns a NodeList (kind of Array), so setting a property on that is not affecting the elements that it contains, but only the NodeList itself, which has no effect.
You could set the class name of the first element, for example, like this:
y[0].className = "contentEditListItemActive";
Or, if you want all elements have their class name changed, you could iterate over the NodeList:
for(var i = 0; i < y.length; i++) {
y[i].className = "contentEditListItemActive";
}