I am trying to search a page for links that contain the word playgame. If they found then I add them to an array. After that Select a random value from the array and use window.location. My problem is that it says my indexof is undefined. I not sure exactly that what means as I am still learning to use this feature of javascript.
example of link
<img src="http://games.mochiads.com/c/g/running-lion-2/_thumb_100x100.jpg">
javascript
var gameLinks = document.getElementsByTagName("a");
if (gameLinks.href.indexOf("playgame") != -1) {
var links = [];
links.push(gameLinks.href);
var randomHref = links[Math.floor(Math.random() * links.length)];
window.location = randomHref;
}
My problem is that it says my indexof is undefined
Not indexOf, the thing you're calling it on. gameLinks is a NodeList, it doesn't have an href property. You need to loop through the contents of the list to look at the individual element's href property. E.g.:
var index, href, links, randomHref, gameLinks;
gameLinks = document.getElementsByTagName("a");
// Loop through the links
links = [];
for (index = 0; index < gameLinks.length; ++index) {
// Get this specific link's href
href = gameLinks[index].href;
if (href.indexOf("playgame") != -1) {
links.push(href);
}
}
randomHref = links[Math.floor(Math.random() * links.length)];
window.location = randomHref;
More to explore:
DOM2 Core
DOM2 HTML
DOM3 Core
HTML5 Web Application APIs
Related
I am building a plugin for a CMS that has lots of different templates. As part of the plugin I am pulling text from a specific description box on the page. The problem is that every template has a different class name for the description box. I have gotten the plugin to work on a specific template that uses ".class1" but I would like to make it work no matter what template its installed on.
I basically want to put the class names from each template in an array and then check and see which one is on the page. I then want to store the matched class name in a variable that I can use.
This will loop through an array of classes and check to see if there are any elements matching each class on the page. The matched class names get pushed into a new array.
var classes = [".abc", ".def", ".ghi"];
var found = [];
for(var i = 0; i < classes.length; i++) {
if($(classes[i]).length > 0) {
found.push(classes[i]);
}
}
If you're certain that only one class in the initial list will be found, you can stop after your first hit:
var classes = [".abc", ".def", ".ghi"];
var found;
for(var i = 0; i < classes.length; i++) {
if($(classes[i]).length > 0) {
found = classes[i];
break;
}
}
You can use document.querySelector() to find the element with one of the classes.
Note that if you want to find more than one instance - document.querySelectorAll() will create a node list.As #Hydrothermal says - if there are multiple elements with that class - you will need to push them into an array and using an index [0] to identify them.
var templates = ["first-template", "second-template", "third-template"];
var currentTemplate;
templates.forEach(function(template){
let test = document.querySelector("." + template);
if(test !== null) {currentTemplate = template};
})
console.log(currentTemplate); // gives secondTemplate
<div class="second-template">I am a template</div>
I have been stuck on this as I am not the best with mixing arrays + string matches.
What I would like to do is return the index number within an array based on a partial match from a string. Full use case; check if text exists in a URL based off values within an array - and return the index of array position.
Don't mind JS or jQuery but whichever might be most efficient is fine (or works).
Current attempt:
Example URL = www.site.com/something/car/123
Another Example URL might be www.site.com/something/somethingelse/banana/
(location of snippet to match is not always in the same path location)
var pageURL = location.href;
var urlArray = ['/car/','/boat/','/apple/','/banana/'];
function contains(urlArray, value) {
var i = urlArray.length;
while (i--) { if (urlArray[i].indexOf(pageURL)) console.log(i)} console.log('Not Found');}
alternate Using jQuery (not sure where to use indexOf or another jQuery alternative (.search / .contains)):
urlArray.each(function(){
$.each(this, function(index) { } ) });
Expected output for first URL would be 0, second example URL would be 3.
Help is much appreciated!
You can iterate over the array with findIndex() to get the index if the includes() the string.
This will go through the urlArray and return the index of the first match (and -1 if a match isn't found).
let URL1 = "www.site.com/something/car/123"
let URL2 = "www.site.com/something/somethingelse/banana/"
let urlArray = ['/car/','/boat/','/apple/','/banana/'];
let index1 = urlArray.findIndex(str => URL1.includes(str))
let index2 = urlArray.findIndex(str => URL2.includes(str))
console.log(index1, index2)
You can also use a forEach() loop on the urlArray to get each word from the array and check if it exist in url or not.
var url = 'www.site.com/car/somethingelse/banana/';
var urlArray = ['/car/', '/boat/', '/apple/', '/banana/'];
urlArray.forEach(function(word){
//if word exist in url
var wordIndex = url.indexOf(word);
if(wordIndex !== -1){
console.log(wordIndex);
}
});
NOTE includes() do not work in IE browser and older versions thus to make it work on all browsers the recommended way is to avoid arrow functions with includes() and instead use plain function with indexOf()
To return the array index:
var url = 'www.site.com/car/somethingelse/banana/';
var urlArray = ['/car/', '/boat/', '/apple/', '/banana/'];
urlArray.forEach(function(word, index){
//if word exist in url
if(url.indexOf(word) !== -1){
console.log(index);
}
});
for (var i = 0; i < urlArray.length; i++) {
if(pageURL .indexOf(urlArray[i])>-1){
console.log(pageURL.indexOf(urlArray[i])));
}
}
$.get("http://en.wikipedia.org/wiki/Afghanistan", function(response) {
var elements = $.parseHTML(response);
var wiki = $(elements).find('#mw-content-text').find("p");
var ps = [];
var arrayLength = wiki.length;
for (var i = 0; i < arrayLength; i++) {
if (wiki[i].innerHTML === "") {
break;
}
var item = wiki[i]
ps.push(item);
$("#fakediv").append(ps);
}
I am trying to remove the links from the variable item, but I can't seem to find any examples of how to do this from a variable - everything assumes that I'll be using a selector.
I've tried .removeAttr("href"), but that doesn't seem to work and I'm not quite sure how to remove links and leave the text.
You say you want to unlink the links, but you are looping over paragraph elements and trying to remove its attribute. I doubt the paragraph has an href attribute.
So you need to find the anchors inside the paragraph tags
var item = wiki.eq(i);
item.find("a").removeAttr("href")
ps.push(item);
or
var item = wiki.eq(i);
item.find("a").contents().unwrap();
ps.push(item);
I have the following line of code:
document.getElementById("question_*").setAttribute("disabled", "false");
I want to use a form of wildcard for the element ID. The script is run and used by lots of different buttons, they all have ID's of question_something - is it possible to make this setAttribute to make the button enabled for various ID's?
<button id="question_1a" onClick="nextQuestion(this.id)" disabled>Next question</button>
EDIT:
I've switched to a classname as suggested. Buttons now are:
<button id="question_1a" class="nextButton" disabled>Next question</button>
I've added the following line to make this not disabled:
var elems = document.getElementsByClassName('nextButton').setAttribute("disabled", "false");
But I get: Uncaught TypeError: Object # has no method 'setAttribute'
You can't use wildcards with document.getElementById(), you can, however, with document.querySelectorAll():
var elems = document.querySelectorAll('button[id^="question_"]');
This, of course, requires a relatively up to date browser; on the other hand using a class-name (for example question) to associate those elements would allow you to use:
var elems = document.getElementsByClassName('question');
Or:
var elems = document.querySelectorAll('button.question');
I tried doing this: var elems = document.getElementsByClassName('nextButton').setAttribute("disabled", "false"); - but I get: Uncaught TypeError: Object # has no method 'setAttribute'
That's because you can't modify the properties of a NodeList all at once, you can, however, use a for (){...} loop, or similar to do so:
Using for(){...}:
var elems = document.getElementsByClassName('question');
for (var i = 0, len = elems.length; i < len; i++){
elems[i].disabled = false; // to make them all enabled
}
JS Fiddle demo.
Or using forEach (up to date browsers):
var elems = document.getElementsByClassName('question');
[].forEach.call(elems, function(a){
a.disabled = false; // will make all elements enabled
});
JS Fiddle demo.
References:
Array.prototype.forEach().
CSS attribute-selectors.
document.getElementById().
document.getElementsByClassName().
document.querySelector() compatibility.
document.querySelectorAll() compatibility.
Function.prototype.call().
JavaScript for loop.
That's precisely what classes are for:
<button class="question" id="question_1a" onClick="nextQuestion(this.id)" disabled>Next question</button>
And
var elems = document.getElementsByClassName("question");
for(var z=0;z<elems.length; z++){
elems[z].setAttribute("disabled", "false")
}
Another possibility, if querySelectorAll or getElementsByClassName (could be shimmed in a similar manner) wasn't available and you wanted to match multiple IDs.
HTML
<button>Question</button>
<button id="question_1a">Question</button>
<button id="question_1b">Question</button>
<button id="question_1c">Question</button>
<button id="question_1d">Question</button>
<button id="question_2a">Question</button>
Javascript
function getElementsById(regex) {
var tags = document.getElementsByTagName('*'),
tagsLength = tags.length,
matches = [],
index,
tag;
for (index = 0; index < tagsLength; index += 1) {
tag = tags[index];
if (regex.test(tag.id)) {
matches.push(tag);
}
}
return matches;
}
console.log(getElementsById(/^question_1[a-z]?$/));
Output
[button#question_1a, button#question_1b, button#question_1c, button#question_1d]
On jsFiddle
Then you can iterate this array and set the attributes
And the getElementsByclassName shim
function getElementsByClassName(node, className) {
var array = [],
regex = new RegExp("(^| )" + className + "( |$)"),
elements = node.getElementsByTagName("*"),
length = elements.length,
i = 0,
element;
while (i < length) {
element = elements[i];
if (regex.test(element.className)) {
array.push(element);
}
i += 1;
}
return array;
}
Nope wildcard isn't supported. But to solve this problem you can use jQuery to do the same.
P. S. I will try to post code once I am back at desk
Update
agree David Thomas & Beemo's code hint that should solve your problem
You can use JQuery $("[id^='question_']") selector to get all elements with an id starting by question_
I would like to get all the elements/nodes in an HTML page which contain attributes that start with something (again, the attribute names start with something, not their values!). For example, TinyMCE has a tendency of adding custom attributes to the elements it saves, like "mce_style", "mce_href", "mce_bogus", etc. I would like to have something like the CSS3 selector for attribute values, [attr^="mce_"], but not for the values, the attribute names.
Of course, I can iterate through all DOM nodes and their attributes and check them one by one, but I was wondering whether there is a more efficient way.
Please don't give me TinyMCE-specific answers, I'm pretty sure there's a flag which would prevent TinyMCE for saving these attributes, but the question is generic.
here's a simple demo to find all elements that contain an attribute starting with mce_. might need some refinements.
function getMCE() {
var el, attr, i, j, arr = [],
reg = new RegExp('^mce_', 'i'), //case insensitive mce_ pattern
els = document.body.getElementsByTagName('*'); //get all tags in body
for (i = 0; i < els.length; i++) { //loop through all tags
el = els[i] //our current element
attr = el.attributes; //its attributes
dance: for (j = 0; j < attr.length; j++) { //loop through all attributes
if (reg.test(attr[j].name)) { //if an attribute starts with mce_
arr.push(el); //push to collection
break dance; //break this loop
}
}
}
return arr;
}
console.log(getMCE())
Try this:
FUNCTIONS
//custom selector expression
$.extend($.expr[':'],{
attr:function(o,i,m){
var attrs=$.getAttrAll(o),re=m[3],found=false;
$.each(attrs,function(k,v){
if(new RegExp(re).test(v)) { return found=true;}
});
return found;
}
});
// get all atrributes of an element
$.getAttrAll=function(el){
var rect = [];
for (var i=0, attrs=el.attributes, len=attrs.length; i<len; i++){
rect.push(attrs.item(i).nodeName);
}
return rect;
};
`
USAGE
// calling custom selector expression :attr(regexp)
$(function(){
$('body').find(':attr("^mce_")').css({background:'yellow'});
});
HTML
<body>
<p mce_style="height:50px" id="x" data-hello="hello">selected</p>
<div not_mce_bogus="abc">not_mce_bogus</div>
<div mce_href="http://rahenrangan.com">selected</div>
<p>othrs</p>
</body>
One option, if you don't mind temporarily altering your DOM, is to extract your HTML into a string and search for the attributes via RegExp. When you find the attributes, you could append a "needle" in the DOM so that you can use jQuery to select the elements.
Here is a working concept (run with console open):
http://jsfiddle.net/skylar/N43Bm/
Code:
$.fn.extend({
findAttributes: function(attribute) {
var attributeFinder = new RegExp(attribute + '(.+)="', "gi");
var elementHTML = this.html().replace(attributeFinder, "data-needle='pin' "+attribute+"$1=\"");
this.html(elementHTML);
return this.find("[data-needle=pin]").removeAttr('data-needle');
}
});
console.log($("body").findAttributes('mce_'));
Note: my regexp is not great. You'll have to take better care than I have in this example.
Try this: (I tried putting * instead of a tag but it colored all the elements including those who do not have mce_style attribute as well)
a[mce_style] { color : red; }
Demo : http://jsfiddle.net/Tcdmb/
More info : https://developer.mozilla.org/en/CSS/Attribute_selectors