So i am wondering how i can replace two or more at once with single replace call.
I haven't tried anything so far, as i don't have a clue how i can do that.
let links = {
_init: "https://%s.website.com/get/%s",
}
So as you can see here i have a link with 2x %s which i want to replace.
I am thinking about something like this:
links._init.replace('%s', 'name', 'query')
obviously it won't work. So i am wondering if there is other way of doing it.
I know that languages like python, c# etc have similar feature.
One option is to use a replacer function, and an array that you shift() from:
let links = {
_init: "https://%s.website.com/get/%s"
};
const replaceWith = ['name', 'query'];
const replaced = links._init.replace(
/%s/g,
() => replaceWith.shift()
);
console.log(replaced);
If you don't want to mutate the existing array, you can also use a counter that gets incremented on every iteration:
let links = {
_init: "https://%s.website.com/get/%s"
};
const replaceWith = ['name', 'query'];
let i = 0;
const replaced = links._init.replace(
/%s/g,
() => replaceWith[i++]
);
console.log(replaced);
Related
I learning ES6 and try to use new for me endsWith. Before this I used includes in some of my scripts, and I thought that mechanic will be same. I picked a casual task: I have domains list and want to filter all "cn" domains. Logic is:
let ends = [".cn",".tw",".jp"]
for(let i=0;i<arrayOfDomains.length;i++){
const host = /https?:\/\/(www\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]+/.exec(arrayOfDomains[i])[0];
console.log(host.endsWith(ends))
}
and result of console.log all false. Is there a way to use array in endsWith?
No, there isn't a way to use an array in endsWith, one option is to declare another function that uses the ends array and host variable as parameters to check it.
You can try something like this:
let ends = [".cs", ".com"];
let host = "www.page.com";
let hostEndsWith = (host, ends) => {
let value = false;
value = ends.some(element => {
return host.endsWith(element);
});
console.log(value);
};
hostEndsWith(host, ends);
You can copy that code in JSFiddle to test it.
Here is the information about the endsWith function endsWith informartion
I hope this helps you!
Here's the line:
const parent = document.querySelector(`#${parentId}`);
I know what the const parent, document.querySelector() and parentId mean and do.
I'm struggling to find out what the #, $ and {} do as a combination.
Here's the full .js:
(function(document) {
const buttons = document.querySelectorAll('[data-next]');
for (const item of buttons) {
const parentId = item.getAttribute('data-parent');
const parent = document.querySelector(`#${parentId}`);
console.log(parent);
const nextDivId = item.getAttribute('data-next');
const nextDiv = document.querySelector(`#${nextDivId}`);
if (!nextDiv) {
console.error('could not find next div for button ', item);
}
item.addEventListener('click', function() {
nextDiv.classList.toggle('hidden');
parent.classList.toggle('hidden');
});
}
})(document);
It is called Template Literals. From the documentation:
Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called "template strings" in prior editions of the ES2015 specification.
Technically the code creates a string for document.querySelector() which will at the end of the day a selector for the parent's id.
Example code:
const parentId = 'randomid';
const result = `#${parentId}`;
console.log(result);
So you can think about that code as the following:
const parentId = item.getAttribute('data-parent');
const selector = `#${parentId}`;
const parent = document.querySelector(selector);
Read further here: Template Literals
I hope this helps!
${parentId} is a template literal expression
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
Here it is saying, "get the variable parentId and prepend a hashtag, to indicate an id for the querySelector() function."
In the below code for example, the line renders as:
const parent = document.querySelector("#a")
const parentId = "a"
const parent = document.querySelector(`#${parentId}`)
parent.style.color = "#f00"
<div id="a">Text</div>
It's called a template literal.
You can think about it as putting some parsed code into a string.
So, if you want to put a variable into the string '#', you can do like this:
const someId = 'someid';
const idWithHashTag = `#${someId}`;
You have to use the backticks (), and then you can use${}` and do something inside the curly braces.
boxIds => an array of unique file IDs received.
Every cluster has an array of files.
I am looking to iterate over each cluster and look for a matching file id, if that id exists, remove that file from that specific cluster.
For some reason I am getting erroneous results while using splice(), since it's mutating the original array this creates a result that returns an array and removes every other file.
moveFilesToCluster: function(state,payload){
const boxIds = payload.boxIds;
const moveToClusterId = payload.clusterId;
let fileAddToCluster = [];
state.assignmentClusters.forEach(cluster =>{
cluster.files.slice().forEach((file,index) =>{
if (_.includes(boxIds, file.id)){
fileAddToCluster.push(file);
cluster.files.splice(index,1)
}
});
});
}
I also tried (in this code) to add slice() before the forEach() (see above), but that isn't really delivering.
I also tried (in this code) to add slice() before the forEach() (see above), but that isn't really delivering.
As I said in a comment, I find it surprising that that isn't working. Using slice as in your question clones cluster.files and then loops through the clone, and you're modifying the original. That should work. It's not how I'd recommend doing it, but it should work.
The classic way to do this would be with filter:
const boxIds = payload.boxIds;
const moveToClusterId = payload.clusterId;
let fileAddToCluster = [];
state.assignmentClusters.forEach(cluster =>{
cluster.files = cluster.files.filter(file) {
if (_.includes(boxIds, file.id)){
fileAddToCluster.push(file);
return false;
}
return true;
});
});
But if you want to modify the array in place, you could use a boring old while loop and only increment the index if you don't remove the entry:
const boxIds = payload.boxIds;
const moveToClusterId = payload.clusterId;
let fileAddToCluster = [];
state.assignmentClusters.forEach(cluster =>{
let i = 0;
while (i < cluster.files.length) {
if (_.includes(boxIds, file.id)){
fileAddToCluster.push(file);
cluster.files.splice(i, 1);
} else {
++i;
}
}
});
I'm creating an array of DOM elements (HTML) without having to look up into the DOM, like so:
const frames = [
...document.createRange()
.createContextualFragment(
new String(
new Array(options.length)
.fill()
.map((v, i) => `<div class="page"><iframe src="./renders/page-${i + 1}"></iframe></div>`)
)
)
.querySelectorAll('div')
].map((page, index) => _addPageWrappersAndBaseClasses(page, index))
Is there a more sane way of doing this?
Sure, just don't put everything on one line. Instead make sensible use of variables and line breaks.
const divStrings = new Array(options.length)
.fill()
.map((v, i) =>
`<div class="page"><iframe src="./renders/page-${i + 1}"></iframe></div>`
)
const frag = document.createRange().createContextualFragment(new String(foo))
const divs = [...frag.querySelectorAll('div')]
const frames = divs.map(_addPageWrappersAndBaseClasses)
Only change to the code above, other than the formatting and variables, is that the anonymous callback to .map at the end was extraneous. I changed it to pass the function being called directly.
You could get rid of a variable or two, so it doesn't need to be quite that drawn out, but there's not really any benefit to packing everything into a single expression.
Yes, it would be both more efficient and more concise to use regular DOM methods.
for(let i = 0; i < options.length; i++) {
const page = document.createElement("div");
page.className = "page";
const frame = document.createElement("iframe");
frame.src = `./renders/page-${i + 1}`;
page.appendChild(frame);
_addPageWrappersAndBaseClasses(page, i);
}
You should also try to avoid parsing HTML with strings in JavaScript.
I am learning JS by my own and I have created first little script :). Script is counting the number of signs for the tag tittle of a webpage to be between 50 and 60 etc.... Below there is one button that resets all the data in the script and its working 100% but I have a question - Can I use some kind of loop instead of that code that I have created? A loop that will be reseting all elements below. Thx for Your help :) and advice...
// reset Title tag check
document.getElementById("resetTitleBtn").addEventListener("click", function(){
document.getElementById('inputTitleTag').value = "";
document.getElementById('titleTag').innerHTML = "";
document.getElementById('example').innerHTML = "";
document.getElementById("tytul").style.color = "";
document.getElementById("good").innerHTML = "";
});
While I don't think in this case a loop is necassary, you could do something like this:
// reset Title tag check
document.getElementById("resetTitleBtn").addEventListener("click", function(){
var tags = ['titleTag', 'example', 'good'];
for(var i = 0; i < tags.length; i++){
document.getElementById(tag).value = "";
}
document.getElementById('inputTitleTag').value = "";
document.getElementById("tytul").style.color = "";
});
Yes, it can be done with a loops:
var resets = [
{id: 'inputTitleTag', props: ['value']},
{id: 'titleTag', props: ['value']},
{id: 'example', props: ['innerHTML']},
{id: 'tytul', props: ['style', 'color']},
{id: 'good', props: ['innerHTML']}
]
document.getElementById("resetTitleBtn").addEventListener("click", function(){
resets.forEach(function(reset) {
reset.props.length === 1 ? document.getElementById(reset.id)[reset.props[0]] = "" : document.getElementById(reset.id)[reset.props[0]][reset.props[1]] = "";
});
});
You can group these ids in an array and loop over the array for applying similar operation.
Since inputTitleTag and tytul do not share operation with others, there is no point in looping over them.
document.getElementById("resetTitleBtn").addEventListener("click", function(){
var ids = ['titleTag', 'example', 'good'];
document.getElementById('inputTitleTag').value = "";
document.getElementById("tytul").style.color = "";
ids.forEach(function(id){
document.getElementById(id).innerHTML = "";
});
});
If what you are concerned about is being more dry. Or do not repeat yourself then you could alias a few of your more commonly used functions. Then looping mechanisms are also nice when a pattern is noticed such as all three of the same prop. Usually two or less of the same prop is pointless for a loop as a minimum loop is usually 2-3 lines to declare.
const clear = (element, prop) => element[prop] = "";
const get = (id) => document.getElementById(id);
get("resetTitleBtn").addEventListener("click", () => {
['titleTag', 'example', 'good'].forEach(id => clear(get(id), 'innerHTML'));
clear(get('inputTitleTag'), 'value'));
clear(get('tytul').style, 'color'));
});
This doesn't necessarily improve this sample segment of code but can lead to a more dry pattern throughout the project for commonly used functions.
You might consider using classes to identify different elements requiring common initialization and select them that way.
var resetValueEls = document.getElementsByClassName('initValue');
var resetInnerHTMLEls = document.getElementsByClassName('initInnerHTML');
var resetColorEls = document.getElementsByClassName('initColor');
Array.prototype.forEach.call(resetValueEls, function(x) {x.value = ""})
Array.prototype.forEach.call(resetInnerHTMLEls, function(x) {x.innerHTML = ""})
Array.prototype.forEach.call(resetColorEls, function(x) {x.style.color = ""})
then, each HTML tag that requires initialization gets a class or combination thereof e.g. <DIV class="initInnerHTML initColor"/>.
The benefit of this strategy is that if you have many tags to initialize, despite having many ids, you have a small number of classes to keep track of in your initializer.