I've created HTML builder (finally!)
It just has methods: create div, span, p, br.
As you can see in console.logs it has nesting and chaining behavior.
And for detecting nesting and chaining I have item instanceof Class
But it doesn't show me correct return when I have nesting condition.
Need help to find the mistake and get output in first console.log =
<div><p>Hello</p><p>World</p></div>
class Templater {
constructor() {
this.arr = [];
this.nesting = false;
}
transform(tags) {
return tags.join("");
}
div(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<div>${this.transform(tags)}</div>`)
return this;
}
span(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<span>${this.transform(tags)}</span>`);
return this
}
br(argument) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
if (argument) {
throw new Error('Nested content is not allowed');
} else {
this.arr.push(`<br>`);
return this;
}
}
p(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<p>${this.transform(tags)}</p>`);
return this
}
toString() {
if (this.nesting) {
this.nesting = false;
let qwe = [...this.arr];
this.arr = [];
return qwe[qwe.length-1];
} else {
let qwe = [...this.arr];
this.arr = [];
return qwe.join('');
}
}
}
const template = new Templater();
console.log(template.div(
template.p('Hello'),
template.p('World')
).toString());
console.log(template.div().toString());
console.log(template.div('Hello').p('fix').toString());
Worked for me with :
console.log(template.div(
template.p('Hello').p('World').toString()
).toString());
Related
Suppose I have this code:
function GraphFactory() {
this.nodeNames = [];
this.pinnedNodes = [];
this.initPinnedNodes = function(nodes) {
if (nodes) {
this.pinnedNodes = nodes;
} else {
this.pinnedNodes = [];
}
}
this.checkIfPinned = function(node) {
if (this.pinnedNodes.indexOf(node) > -1) {
return true;
} else {
return false;
}
}
this.addToPinnedNodes = function(name) {
this.pinnedNodes.push(name);
return true;
}
this.removeFromPinnedNodes = function(name) {
this.pinnedNodes.splice(this.pinnedNodes.indexOf(name), 1);
return true;
}
}
let graphFactory = new GraphFactory();
Right now i can access both the function
graphFactory.checkIfPinned(label);
but also directly the variable
graphFactory.pinnedNodes
How would I set things up so only the functions, but not the variables could get accessed?
Use variables instead of properties on the object.
let nodeNames = [];
They'll be closed over by your dynamically assigned instance methods.
Or see this question for the modern approach.
With the current construct, you can use a closure per object, practically a local variable in your constructor function:
function GraphFactory() {
var nodeNames = [];
var pinnedNodes = [];
this.initPinnedNodes = function(nodes) {
if (nodes) {
pinnedNodes = nodes;
} else {
pinnedNodes = [];
}
}
this.checkIfPinned = function(node) {
if (pinnedNodes.indexOf(node) > -1) {
return true;
} else {
return false;
}
}
this.addToPinnedNodes = function(name) {
pinnedNodes.push(name);
return true;
}
this.removeFromPinnedNodes = function(name) {
pinnedNodes.splice(this.pinnedNodes.indexOf(name), 1);
return true;
}
}
let graphFactory = new GraphFactory();
However such variables will not be accessible to methods you add later, from outside. For example that nodeNames exists in vain this way.
When looping through an array to find if the array contains a word that I am looking for, the loop always returns 'false' when if I console.log out the what is being compared I can clearly see that the word I am looking for (collectionNameLookingFor) is in the array (collectionNameArray) so it should return true.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayofCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
function saveContentToDb(req, res) {
const db = getDb();
const pageDetails = req.body;
let saveType;
db.db(pageDetails.databaseName).listCollections().toArray((error, collections) => {
if (error) {
throw error;
} else {
collections.map(collection => (collection.name)).forEach(collectionNameArray => {
const collectionNameLookingFor = req.body.page;
const check = checkCollectionNames(collectionNameArray, collectionNameLookingFor);
console.log('===========Looking to see if it is true or false==========');
console.log(check);
console.log(`Name of collection in Database: ${collectionNameArray} ::: ${collectionNameLookingFor}`);
console.log('==========================================================');
if (check === true) {
saveType = 'updated';
console.log(`saveType = ${saveType}`);
} else {
saveType = 'created';
console.log(`saveType = ${saveType}`);
}
});
}
});
}
You might need to check against collectionName, because that is the parameter you hand over, beside arrayOfCollections, instead of the array itself.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayOfCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
Short Version:
function checkCollectionNames(arrayOfCollections, collectionName) {
return arrayOfCollections.includes(collectionName);
}
This question already has an answer here:
Is there a way to have lexical `this` in methods using the ES6 shorthand method notation?
(1 answer)
Closed 4 years ago.
I'm currently working on a Eloquent JavaScript's object assignments and I'm wondering if there is any way that I can use this inside iterator's next() method (see the code)
class Group {
constructor() {
this.members = [];
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
[Symbol.iterator]() {
let current = 0;
let last = this.members.length - 1;
const that = this;
return {
next() {
if (current <= last) {
return {
done: false,
value: that.members[current++]
}
} else return { done:true }
}
}
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
As you can see there I'm using this weird const that = this pattern. Is there any way I can get rid of it? Besides using arrow function and extracting iterator to a separate class, as suggested in the solution.
The sortest way, could be an implementation of a default iterator of the object in the constructor section and use yield* expression for delegating to another generator of the array this.members.
constructor() {
this.members = [];
this[Symbol.iterator] = function* () {
yield* this.members;
}
}
class Group {
constructor() {
this.members = [];
this[Symbol.iterator] = function* () {
yield* this.members;
}
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
you can use the arrow function
class Group {
constructor() {
this.members = [];
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
[Symbol.iterator]() {
let current = 0;
let last = this.members.length - 1;
return {
next: () => {
if (current <= last) {
return {
done: false,
value: this.members[current++]
}
} else return { done:true }
}
}
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
I'm trying to do the equivalent of .GroupBy(key => key.IdItem).Select(item => item.Single()); from linq to typescript.
What I've tried:
let parents = value.reduce((parents, parent) => ({
...ubc,
[parent.IdItem]: [...(parents[u.IdItem] || []), parent],
}), {}) as Array<ItemsViewModel>;
Array.prototype.map.call(parents, parent => {
if (parents.length > 1) {
throw new Error('The input sequence contains more than one element');
}
else if (!parents.length) {
throw new Error('The input sequence is empty');
}
return parent[0];
});
What am I doing wrong?
You can try it like this --
let parentsById =
value.reduce((dict, parent) => {
let { IdItem } = parent;
dict[IdItem] = dict[IdItem] || [];
dict[IdItem].push(parent);
return dict;
}, {});
let result =
Object.keys(parentsById)
.map(k => {
let parents = parentsById[k];
if(parents.length !== 1) { throw new Error("Must contain a single item"); }
return parents[0];
});
Also, if you simply want unique parents, you can use a hashet of seen IDs --
let result = [];
let seenIds = {};
for(let parent of value) {
let { IdItem } = parent;
if(!seenIds[IdItem]) {
result.push(parent);
seenIds[IdItem] = true;
}
}
I have a Javascript class defined as below:
function Node(init, parent) {
this.value = init;
this.children = [];
this.updateChildren(this.value);
}
Node.prototype.updateChildren = function(value) {
this.children.push(value);
};
When I run it.. i receive the error,
this.updateChildren() is not defined.
Any clue what I am missing here ?
Full code here :
'use strict';
var millionNumbers = [];
for (var i = 2; i< 1000000; i++) {
if (!millionNumbers[i]) {
millionNumbers[i] = new Node(i, null);
}
}
function Node(init, parent) {
this.value = init;
this.children = [];
if (parent) {
this.parent = parent;
}
var newValue;
if (isEven(this.value)) {
newValue = this.value/2;
} else {
newValue = (this.value * 3) + 1;
}
//whether newValue is 1 or something else, we still have add it to the children list
this.updateChildren(newValue);
if (millionNumbers[newValue]) {
var chainedNode = millionNumbers[newValue];
this.children.concat(chainedNode.children);
}
if (newValue === 1) {
this.endChain();
} else {
new Node(newValue, this);
}
}
Node.prototype.updateChildren = function(value) {
this.children.push(value);
if(this.parent) {
this.parent.updateChildren(value);
}
};
Node.prototype.endChain = function() {
if (!millionNumbers[this.value]) {
millionNumbers[this.value] = this;
this.parent = null;
}
};
function isEven(value) {
if (value % 2 === 0) {
return true;
} else {
return false;
}
}
The for loop instantiates Node objects before Node.prototype.updateChildren is set, so within the Node constructor, this.updateChildren is still undefined.
To fix the problem, just move the for loop to the end of the file.
Also: Best of luck with the Collatz conjecture!
think you are calling these classes without defining them first.
You can try this way:
function updateChildren(value) {
this.children.push(value);
};
function Node(init, parent) {
this.value = init;
this.children = [];
this.updateChildren(value);
}
Node.prototype.updateChildren(value);