here is the deal, i have the following jquery code that should add the array values to specific #id, buf it does not replace the code, only add more, and i need a little help to make it replace the html on othe link click.
Code:
function changeClass(curClass){
switch(curClass){
case "Schoolgirl":
case "Fighter":
var charSkillsNames = ["text1","text2","text4","text5"];
//loop show array values
listSkillsNames(charSkillsNames);
break;
}
}
function listSkillsNames(arr){
var length = arr.length,
element = null;
$("#skills").html(function(){
for (var i = 0; i < length; i++) {
element = arr[i];
$(this).append("<li>"+element+"</li>");
}
});
}
this works well but i need it to replace the html inside the "#skills" id when i click on the link that makes it work
PS: problem is really here
The issue is that you don't empty the HTML of #skills element. Use $("#skills").html("") to empty it.
function listSkillsNames(arr){
var length = arr.length,
element = null;
var $skills = $("#skills");
$skills.html(""); // empty the HTML
for (var i = 0; i < length; i++) {
element = arr[i];
$skills.append("<li>"+element+"</li>"); // append new items
}
}
The problem is because you are keep appending new items to the element always without removing the existing items.
Just empty the skill element, also there is no need to use the .html(function(){}) here
function listSkillsNames(arr) {
var length = arr.length,
element = null;
var $skill = $("#skills").empty();
for (var i = 0; i < length; i++) {
element = arr[i];
$skill.append("<li>" + element + "</li>");
}
}
Related
I'm still working on my word filter. I've tried different things, but I'm always getting stuck with putting my updated words back into the DOM. The goal is to collect all bad words, replace them with a string (like ****) and output that in place of the original term. E.g. having the text "this is a text with a bad word" that would get turned into "this is a text with a **** word". I have an array of bad words stored in and declared as badStuff.
First, I get all inputs type = text and turn that HTML collection into an array. Same with the textareas. Then I merge these arrays into submittedWords.
I use a function that compares and replaces words as follows:
function validateText() {
// get the values from all input fields
for (let i = 0; i < inputs.length; i++) {
submittedWords.push(inputs[i].value);
}
// add the values from all textareas
for (let i = 0; i < textareas.length; i++) {
submittedWords.push(textareas[i].value);
}
// loop through the submitted words and if one matches an item in badStuff,
// replace the original term with a censored version
for ( let i = 0; i < submittedWords.length; i++) {
if (badStuff.includes(submittedWords[i].toLowerCase())) {
submittedWords[i] = submittedWords[i].replace(submittedWords[i], "****");
//return submittedWords[i] into DOM
// return? print?
}
}
// clear submittedWords array after each check
submittedWords = [];
}
validateText();
Now my problem is that I'm not sure how to output my results into the DOM, so that every bad word gets replaced with **** whenever validateText() runs and encounters one. I know how to replace text within, say, some <p> or other tag or exchange/update CSS classes via JS to display results. But here, I have an array with elements from various input fields and textareas that need to be replaced.
Maybe I can't see the obvious.
You do not need to store everything in array and then loop twice. Doing so you will leave control to the DOM element.
Shorten your code to:
for (let i = 0; i < inputs.length; i++) {
if (badStuff.includes(inputs[i].value.toLowerCase())) {
inputs[i].value = inputs[i].value.replace(inputs[i].value, "****");
}
}
for (let i = 0; i < textareas.length; i++) {
if (badStuff.includes(textareas[i].value.toLowerCase())) {
textareas[i].value = textareas[i].value.replace(textareas[i].value, "****");
}
}
On the other hand
input and textarea fields may have many words that are in badStuff array so badStuff.includes(full_value) will not be sufficient for you, instead your approach should be
var badStuff = ["bad1", "bad2", "bad3"];
var str = "hello bad1, how bad2"
badStuff.some(v => {
if (str.includes(v)) {
str = str.replace(v, "****")
}
})
console.log(str);
UPDATE
Final code for you can be:
for (let i = 0; i < inputs.length; i++) {
badStuff.some(v => {
if (inputs[i].value.toLowerCase().includes(v)) {
inputs[i].value = inputs[i].value.replace(v, "****")
}
})
}
for (let i = 0; i < textareas.length; i++) {
badStuff.some(v => {
if (textareas[i].value.toLowerCase().includes(v)) {
textareas[i].value = textareas[i].value.replace(v, "****")
}
})
}
As long as your element are form fields, you should push the elements instead of their value to the array and the, in your for loop, update their value property if needed. Here is an example:
const badStuff = [
'censure',
'blacklist',
'reprehend'
];
let submittedWords = [];
function validateText() {
const inputs = document.querySelectorAll('input');
// get all the input fields
for (let i = 0; i < inputs.length; i++) {
submittedWords.push(inputs[i]);
}
const textareas = document.querySelectorAll('textarea');
// add all the textareas
for (let i = 0; i < textareas.length; i++) {
submittedWords.push(textareas[i]);
}
// loop through the form field elements and if their value matches an item in badStuff, replace the original value with a censored version
for (let i = 0; i < submittedWords.length; i++) {
const element = submittedWords[i];
if (badStuff.includes(element.value.toLowerCase())) {
element.value = element.value.replace(element.value, "****");
}
}
// clear submittedWords array after each check
submittedWords = [];
}
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
submittedWords = [];
validateText();
})
<form>
<input name="test" type="text" value="" />
<textarea type="text" value=""></textarea>
<input type="submit" value="submit" />
</form>
Hei guys, im struggling with a problem here. I selected all elements from body tag into an array like so :
var DOMelementsOrder = [];
var elements = document.querySelectorAll('body > div');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
DOMelementsOrder.push(element);
console.log(DOMelementsOrder[i].offsetLeft);
}
What i'm trying to reach is to sort the tags in array by theyr prop offset left.
The console in for loop return "40,200,85". What i try to achieve is to sort the tags in DOMelementsOrder in order of theyr offsetLeft.
Any help? Thanks in advance.
ONLY WITH PURE JS
EDIT:
What i have tryed:
function bubbleSort(a, b)
{
var swapped;
do {
swapped = false;
for (var i=0; i < a.length-1; i++) {
if (a[i].b > a[i+1].b) {
var temp = a[i].b;
a[i].b = a[i+1].b;
a[i+1].b = temp;
swapped = true;
}
}
} while (swapped);
}
bubbleSort(DOMelementsOrder, DOMelementsOrder.offsetLeft);
console.log(DOMelementsOrder);
Use the Array.prototype.sort method and pass a compare function to compare the values of offsetLeft for each element.
// qSA doesn't return an array, so we have to convert it first
var elements = Array.prototype.slice.call(document.querySelectorAll('body > div'));
// then we can sort
var orderedElements = elements.sort(function(a, b) {
return a.offsetLeft - b.offsetLeft;
});
I've a list of div
<div data-attr="sel" data-num="1"></div>
<div data-attr="notSel" data-num="2"></div>
<div data-attr="sel" data-num="3"></div>
I'm tryng to get a string only div with the data-attr="sel" set.
function SI_MoveTasks() {
var getSelected = document.querySelector('[data-attr~="sel"]');
var selectedNums = getSelected.dataset.num;
alert(selectedNums);
}
Now i get (1), how can i get the concatenate string (1,3)?
Thanks for support.
DEMO -> http://jsfiddle.net/0d54ethw/
Use querySelectorAll instead of querySelector since the latter only selects the first element as opposed to all of them.
Then use for loop as shown below
var getSelected = document.querySelectorAll('[data-attr~="sel"]');
var selectedNums = [];
for (var i = 0; i < getSelected.length; i++) {
selectedNums.push(getSelected[i].dataset.num);
}
alert(selectedNums.join(','));
You would need to use document.querySelectorAll to get all matching elements. document.querySelector returns only the first matching element, or null if there is none.
function SI_MoveTasks() {
var getSelected = document.querySelectorAll('[data-attr~="sel"]');
console.log(getSelected);
var selectedNums = '(';
for(var i=0; i< getSelected.length; i++) {
if (selectedNums !== '(') {
selectedNums += ',';
}
selectedNums += getSelected[i].dataset.num;
}
selectedNums += ')';
alert(selectedNums);
}
SI_MoveTasks();
Thats a working code, jsFiddle is: https://jsfiddle.net/3kjye452/
The end result I'm after is a JavaScript array containing a list of tag names that are used in the HTML document eg:
div, span, section, h1, h2, p, etc...
I want the list to be distinct and I'm not interested in tags within the <head> of the document (but they can be there if it's a performance hog to exclude them).
This has to work in IE 6, 7, & 8 and I don't want to use jquery.
What would be the most efficient way of doing this?
What you're looking for is document.all.tagName
At the top of my head, a for loop like this should do it (providing that you're gonna filter the tags you don't want on that list)
for(i = 0; i < document.all.length; i++)
{
console.log(document.all[i].tagName);
}
Here is a cross-browser solution:
var tags = {}; // maintains object of tags on the page and their count
var recurse = function(el) {
// if element node
if(el.nodeType == 1) {
if(!tags[el.tagName])
tags[el.tagName] = 0;
tags[el.tagName]++;
}
// recurse through the children
for(var i = 0, children = el.childNodes, len = children.length; i < len; i++) {
recurse(children[i]);
}
}
recurse(document);
// if you want just what's in the body(included)
var bodies = document.getElementsByTagName("body");
for(var i = 0; i < bodies.length; i++)
recurse(bodies[i]);
To get a unique list of tagnames in a document as an array that works in all browsers back to IE 6 and equivalent:
function listTagNames() {
var el, els = document.body.getElementsByTagName('*');
var tagCache = {};
var tagname, tagnames = [];
for (var i=0, iLen=els.length; i<iLen; i++) {
tagname = els[i].tagName.toLowerCase();
if ( !(tagname in tagCache) ) {
tagCache[tagname] = tagname;
tagnames.push(tagname);
}
}
return tagnames;
}
If you think there might be an inherited object property that is the same as a tag name, use a propertyIsEnumerable test:
if (!tagCache.propertyIsEnumerable(tagname)) {
so it will work even in Safari < 2.
Get all tagnames in the document, unique, crossbrowser, plain js:
var els = document.getElementsByTagName('*'), tags = [], tmp = {}
for (var i=0;i<els.length;i+=1){
if (!(els[i].tagName in tmp)){
tags.push(els[i].tagName);
tmp[els[i].tagName] = 1;
}
}
use
if (!(els[i].tagName in tmp)
&& !/head/i.test(els[i].parentNode.tagName)
&& !/html|head/i.test(els[i].tagName))
to exclude the <head>
As you can see I am still a novice in javascript
Why is it so that you can append a Textnode only once? When you add it again somewhere else the first one disappears
I do not need a solution to a problem I was just curious what is causing this behavior.
Example where the textnode is only added to the last element of an array:
function hideAdd(){
var hide = document.createTextNode('Afbeelding verbergen');
var afb = collectionToArray(document.getElementsByTagName('img'));
afb.pop();
var divs = [];
for (i=0; i < afb.length; i++){
divs.push(afb[i].parentNode);
}
console.log(divs);
for ( i = 0; i < divs.length;i++){
divs[i].appendChild(hide);
}
}
This is where you use an unique textnode so it works:
function hideAdd(){
var hide = []
var afb = collectionToArray(document.getElementsByTagName('img'));
afb.pop();
var divs = [];
for (i=0; i < afb.length; i++){
divs.push(afb[i].parentNode);
hide[i] = document.createTextNode('Afbeelding verbergen');
}
console.log(divs);
for ( i = 0; i < divs.length;i++){
divs[i].appendChild(hide[i]);
}
}
Short answer is the DOM is a tree, not a network. Each node can have only one parent. If you could add a node in more than one location, it would have more than one parent.