Categories
JavaScript Answers

How to Create a Form Dynamically with JavaScript?

Sometimes, we want to create a form dynamically with JavaScript.

In this article, we’ll look at how to create a form dynamically with JavaScript.

Create a Form Dynamically with JavaScript

To create a form dynamically with JavaScript, we can use the document.createElement method to create the element.

Then we can use the setAttribute method to set the element attributes.

Then we can use the appendChild method to append the elements into the parent element.

For instance, we can write:

const f = document.createElement("form");
f.setAttribute('method', "post");
f.setAttribute('action', "submit.php");

const i = document.createElement("input");
i.setAttribute('type', "text");
i.setAttribute('name', "username");

const s = document.createElement("input");
s.setAttribute('type', "submit");
s.setAttribute('value', "Submit");

f.appendChild(i);
f.appendChild(s);

document.body.appendChild(f);

to create a form with an input and a submit button.

We write:

const f = document.createElement("form");
f.setAttribute('method', "post");
f.setAttribute('action', "submit.php");

to create a form element with the method and action attributes.

setAttribute takes the attribute name and value as arguments respectively.

Similar, we create the input by writing:

const i = document.createElement("input");
i.setAttribute('type', "text");
i.setAttribute('name', "username");

And the submit button we create by writing:

const s = document.createElement("input");
s.setAttribute('type', "submit");
s.setAttribute('value', "Submit");

Next, we call appendChild on f to append both input elements as children of the form element by writing:

f.appendChild(i);
f.appendChild(s);

And finally, we append the form element as a child of the body element by writing:

document.body.appendChild(f);

Now we should see a form displayed on the screen after running the code that generated from the form.

Conclusion

To create a form dynamically with JavaScript, we can use the document.createElement method to create the element.

Then we can use the setAttribute method to set the element attributes.

Then we can use the appendChild method to append the elements into the parent element.

Categories
JavaScript

Using Generators in JavaScript

In JavaScript, generators are special functions that return a generator object. The generator object contains the next value of an iterable object. It’s used for letting us iterate through a collection of objects by using the generator function in a for...of loop. This means the generator function returned conforms to the iterable protocol.

Synchronous Generators

Anything that conforms to the iterable protocol can be iterated through by a for...of loop. Objects like Array or Map conform to this protocol. Generator functions also conform to the iterator protocol. This means that it produces a sequence of values in a standard way. It implements the next function which returns an object at least 2 properties — done and value. The done property is a boolean value that returns true with the iterator is past the end of the iterate sequence. If it can produce the next item in the sequence, then it’s false. value is the item returned by the iterator. If done is true then value can be omitted. The next method always returns an object with the 2 properties above. If non-object values are returned then TypeError will be thrown.

To write a generator function, we use the following code:

function* strGen() {
  yield 'a';
  yield 'b';
  yield 'c';
}

const g = strGen();
for (let letter of g){
  console.log(letter)
}

The asterisk after the function keyword denotes that the function is a generator function. Generator functions will only return generator objects. With generator functions, the next function is generated automatically. A generator also has a return function to return the given value and end the generator, and a throw function to throw an error and also end the generator unless the error is caught within the generator. To return the next value from a generator, we use the yield keyword. Each time a yield statement is called, the generator is paused until the next value is requested again.

When the above example is execute, we get ‘a’, ‘b’, and ‘c’ logged because the generator is run in the for...of loop. Each time it’s run the next yield statement is called, returning the next value from the list of the yield statements.

We can also write a generator that generates infinite values. We can have an infinite loop inside the generator to keep returning new values. Because the yield statement doesn’t run until the next value is requested, we can keep an infinite loop running without crashing the browser. For example, we can write:

function* genNum() {
  let index = 0;
  while(true){
    yield index += 2;
  }
}

const gen = genNum();
console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);

As you can see, we can use a loop to repeatedly run yield. The yield statement must be run at the top level of the code. That means they can’t be nested inside another callback functions. The next function is automatically included with the generator object that is yielded to get the next value from the generator.

The return method is called when the iterator ends. That is, when the last value is obtained or when an error is thrown with the thrown method. If we don’t want it to end, we can wrap the yield statements within the try...finally clause like in the following code:

function* genFn(){
  try {
    yield;
  } finally {
    yield 'Keep running';
  }
}

When the throw method is called when running the generator, the error will stop the generator unless the error is caught within the generator function. To catch, throw, and catch the error we can write something like the following code:

function* genFn() {
  try {
    console.log('Start');
    yield;
  } catch (error) {
    console.log(`Caught: ${error}`);
  }
}

const g = genFn();
g.next();
g.throw(new Error('Error'))

As you can see, if we run the code above, we can see that ‘Start’ is logged when the first line is run since we’re just getting the first value from the generator object, which is the g.next() line. Then the g.throw(new Error('Error')) line is run which throws an error, which is logged inside the catch clause.

With generator functions, we can also call other generator functions inside it with the yield* keyword. The following example won’t work:

function* genFn() {
  yield 'a'
}

function* genFnToCallgenFn() {
  while (true) {
    yield genFn();
  }
}

const g = genFnToCallgenFn()
console.log(g.next())
console.log(g.next())

As you can see, if we run the code above, the value property logged is the generator function, which isn’t what we want. This is because the yield keyword did not retrieve values from other generators directly. This is where the yield* keyword is useful. If we replace yield genFn(); with yield* genFn();, then the values from the generator returned by genFn will be retrieved. In this case, it will keep getting the string ‘a’. For example, if we instead run the following code:

function* genFn() {
  yield 'a'
}

function* genFnToCallgenFn() {
  while (true) {
    yield* genFn();
  }
}

const g = genFnToCallgenFn()
console.log(g.next())
console.log(g.next())

We will see that the value property in both objects logged has the value property set to ‘a’.

With generators, we can write an iterative method to recursively traverse a tree with little effort. For example, we can write the following:

class Tree {
  constructor(value, left=null, center=null, right=null) {
    this.value = value;
    this.left = left;
    this.center = center;
    this.right = right;
  }

  *[Symbol.iterator]() {
    yield this.value;
    if (this.left) {
      yield* this.left;
    }
    if (this.center) {
      yield* this.center;
    }
    if (this.right) {
      yield* this.right;
    }
  }
}

In the code above, the only method we have is a generator which returns the left, center, and right node of the current node of the tree. Note that we used the yield* keyword instead of yield because JavaScript classes are generator functions, and our class is a generator function since we have the special function denoted by the Symbol.iterator symbol, which means that the class will create a generator.

Symbols are new to ES2015. It is a unique and immutable identifier. Once you created it, it cannot be copied. Every time you create a new Symbol, it is a unique one. It’s mainly used for unique identifiers in an object. It’s a Symbol’s only purpose.

There are some static properties and methods of its own that expose the global symbol registry. It is like a built-in object, but it doesn’t have a constructor, so we can’t write new Symbol to construct a Symbol object with the new keyword.

Symbol.iterator is a special symbol that denotes that the function is an iterator. It’s built in to the JavaScript standard library.

If we have the define following code, then we can built the tree data structure:

const tree = new Tree('a',
  new Tree('b',
    new Tree('c'),
    new Tree('d'),
    new Tree('e')
  ),
  new Tree('f'),
  new Tree('g',
    new Tree('h'),
    new Tree('i'),
    new Tree('j')
  )
);

Then when we run:

for (const str of tree) {
console.log(str);`
}

We get all the values of the tree logged in the same order that we defined it. Defining recursive data structures is much easier than without generator functions.

We can mix yield and yield* in one generator function. For example, we can write:

function* genFn() {
  yield 'a'
}

function* genFnToCallgenFn() {
  yield 'Start';
  while (true) {
    yield* genFn();
  }
}

const g = genFnToCallgenFn()
console.log(g.next())
console.log(g.next())
console.log(g.next())
console.log(g.next())

If we run the code above, we get ‘Start’ as the value property of the first item returned by g.next(). Then the other items logged all have ‘a’ as the value property.

We can also use the return statement to return the last value that you want to return from the iterator. It acts exactly like the last yield statement in a generator function. For example, we can write:

function* genFn() {
  yield 'a';
  return 'result';
}
const g = genFn()
console.log(g.next())
console.log(g.next())
console.log(g.next())
console.log(g.next())

If we look at the console log, we can see that the first 2 lines we logged returned ‘a’ in the value property, and ‘result’ in the value property in the first 2 console.log lines. Then the remaining one has undefined as the value. The first console.log has done set to false, while the rest have done set to true. This is because the return statement ended the generator function’s execution. Anything below it is unreachable like a regular return statement.

Asynchronous Generators

Generators can also be used for asynchronous code. To make a generator function for asynchronous code, we can create an object with a method denoted with the special symbol Symbol.asyncIterator function. For example, we can write the following code to loop through a range of numbers, separating each iteration by 1 second:

const rangeGen = (from = 1, to = 5) => {
  return {
    from,
    to,
    [Symbol.asyncIterator]() {
      return {
        currentNum: this.from,
        lastNum: this.to,
        async next() {
          await new Promise(resolve => setTimeout(
            resolve, 1000));

          if (this.currentNum <= this.lastNum) {
            return {
              done: false,
              value: this.currentNum++
            };
          } else {
            return {
              done: true
            };
          }
        }
      };
    }
  };

}

(async () => {
  for await (let value of rangeGen()) {
    console.log(value);
  }
})()

Note that the value that promise resolves to are in the return statements. The next function should always returns a promise. We can iterate through the values generated by the generator by using the for await...of loop, which works for iterating through asynchronous code. This is very useful since can loop through asynchronous code as if was synchronous code, which couldn’t be done before we had asynchronous generators function and the async and await syntax. We return an object with the done and value properties as with synchronous generators.

We can shorten the code above by writing:

async function* rangeGen(start = 1, end = 5) {
  for (let i = start; i <= end; i++) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i;
  }
}

(async () => {
  for await (let value of rangeGen(1, 10)) {
    console.log(value);
  }
})()

Note that we can use the yield operator with async and await. A promise is still returned at the end of rangeGen, but this is a much shorter way to do it. It does the exact same thing that the previous code did, but it’s much shorter and easier to read.

Generator functions are very useful for creating iterators that can be used with a for...of loop. The yield statement will get the next value that will be returned by the iterator from any source of your choice. This means that we can turn anything into an iterable object. Also, we can use it to iterate through tree structures by defining a class with a method denoted by the Symbol Symbol.iterator, which creates a generator function that gets the items in the next level with the yield* keyword, which gets an item from the generator function directly. Also, we have the return statement to return the last item in the generator function. For asynchronous code we have AsyncIterators, which we can define by using async, await, and yield as we did above to resolve promises sequentially.

Categories
JavaScript

Using JavaScript Sets

In JavaScript, Set objects are objects that hold collections of values. They can be iterated in the order they’re inserted. Each value in a Set may occur only once. This means that a Set in JavaScript is consistent with sets in math.

Because each value in a Set has to be unique, their values will be checked for equality. This is done by using the triple-equals operator for comparison; meaning -0 and +0 are different values.

However, NaN is considered to be equal to itself, even though in other parts of JavaScript it’s not. undefined can also be stored in Sets.

Each Set can be created with a constructor, and has the size property to get the number of items in each Set. Sets can be manipulated via many methods.

These include:

  • add: Adds a new element to the Set and returns the Set with the new element inserted.
  • clear: Removes all elements from a Set.
  • delele(value): Removes the given value from the Set and returns the value that the has function would have returned.
  • entries(): Returns a new iterator containing the value for each item in the Set object, sorted by their insertion order. Each entry has an array with the key and the value. The key will be set to the value of the Set entry.
  • forEach(callbackFn, thisArg): Allows iteration through the entries of the Set and works with the data in the callback function that’s passed in. The value of this in the callback by passing in a variable for the thisArg parameter.
  • keys(): Gets the keys of the Set in a new iterator object that has the value of each element.
  • values(): Gets the values of each Set’s insertion order.
  • Set.prototype[Symbol.iterator]: Returns a new iterator object that has the value of each element in the Set in insertion order.

Defining and Manipulating Sets

To define a Set object, we write:

let set = new Set();
set.add(1);
set.add(5);
set.add(5);

After the three calls to the add function, we should get [1,5] when we log the value of the Set variable, because we can’t have duplicates in a Set object.

This only applies to primitive types. So, if we insert two objects with the same content, both will be in the Set. Only the reference is checked when inserting items into a Set, consistent with the triple-equals check.

For example, if we write:

let set = new Set();

for (let i = 0; i < 5; i++){
  set.add({a: 1, b: 2});
}

Then, we’ll get {a: 1, b: 2} in the Set five times, because each object does not have the same reference in memory.

We can check if an element exists in a Set with the has function. For example, if we have:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

Then if we call the has function:

set.has(1)

It will return true. If we call:

set.has(10)

then it will return false, since the element doesn’t exist in the Set. We can also put expressions into a Set function. If we call has as in the following code:

set.has(Math.sqrt(25));

We still get true, because the expression is computed before it’s passed into the has function’s parameter, so it’s the same as set.has(5).

To get the size of the Set, we can use the size property as in the following code:

set.size

Which would be 8, since there are eight elements in the Set.

To remove an item from the Set, we can use the delete function as in the following code:

set.delete(8)

Then 8 would removed from the set. If we call set.has(8), it’ll be false, because 8 is no longer in the Set.

To iterate through the value of a set, we can use the for...of loop. In the following example, we will loop through the entries:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

for (let item of set){
  console.log(item)
}

In the loop above, we get 1 to 8 logged in the order that they were inserted with add.

To loop through the keys of the Set, we can use the keys() method to get the keys from the Set object. For example, we can write the following code:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

for (let key of set.keys()){
  console.log(key)
}

In the case of Set objects, the key would be the same as the value, so that we would still get 1 to 8 logged in the console when we run the code above. To loop through the values, we can call the values method on the Set object as in the following code:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

for (let value of set.values()){
  console.log(value)
}

As we can see, we got the same values as we did from the keys method. This is because with Sets, keys and values are always the same. To get the keys and values all at once, we can use the entries method along with the destructuring assignment operator to decompose the key and value into their own variables in each entry, as in the following code:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

for (let [key, value] of set.entries()){
  console.log(key, value)
}

We can see that the key and value of each entry of a Set is the same, as we expected.

Converting Sets Into Arrays

To convert a Set into an array, we can use the Array.from method. We pass in the Set as an argument of the from method. For example, we can write:

let set = new Set();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
set.add(7);
set.add(8);

const arr = Array.from(set);
console.log(arr)

From running the code above, we see that arr is an array with the same elements in the same order as the Set. This is handy for removing duplicate elements from an array. To remove duplicates from an array, we can convert it to a Set by using the Set’s constructor and then convert it back to an array with Array.from . We can write the following:

let arr = [1,1,1,1,1,2,2,2,3,4,5,5,6,7,8];
const set = new Set(arr);
arr = Array.from(set);
console.log(arr);

When we log arr in the last line of the code above, we get [1, 2, 3, 4, 5, 6, 7, 8] . This is because we passed arr into the Set’s constructor, which created the Set, where the duplicate values are automatically eliminated. Then we call the Array.from function with set as the argument, so we convert it back to an array. The Array.from function returns an array, so we can assign it back to arr and get back an array with the duplicates removed.

An alternative way to convert a Set into an array is to use the spread operator. For example, we can rewrite the example above by using the spread operator:

let arr = [1,1,1,1,1,2,2,2,3,4,5,5,6,7,8];
const set = new Set(arr);
arr = [...set];
console.log(arr);

We get exactly the same result. This is a bit shorter and does the same thing as the Array.from function since the spread operator will make a copy of the object that it’s spreading.

Doing Mathematical Set Operations on JavaScript Sets

Since we can convert between arrays and Sets, we can apply array operations to them. Sets do not come with any methods for doing things like getting the intersection, difference or union with other Sets. However, since we can convert between arrays and Sets, we can use array functions to do the same thing. For example, if we want to get the intersection between two Sets, we can write:

let set1 = new Set();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

let set2 = new Set();
set2.add(1);
set2.add(2);
set2.add(7);
set2.add(8);

const intersectionBetweenSet1and2 = new Set([...set1]
  .filter(item => set2.has(item)))
console.log(intersectionBetweenSet1and2);

When we log the intersectionBetweenSet1and2 , we get 1 and 2 in the Set, which is what we expect, since 1 and 2 are the only elements that are in both Sets. In the Set constructor, we converted set1 into an array with the spread operator and then called filter on it to only include the items in set1 that are in set2 with the has method called on set2 .

To get the set union of two Sets, we just call the spread operator on both, as in the following code:

let set1 = new Set();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

let set2 = new Set();
set2.add(1);
set2.add(2);
set2.add(7);
set2.add(8);

const unionBetweenSet1and2 = new Set([...set1,...set2])
console.log(unionBetweenSet1and2);

When running the code above, we should see that unionBetweenSet1and2 has the value [1,2,3,4,7,8].Since we passed both Sets into the array and spread them with the spread operator, we created an array with all the elements in the array. Then the set constructor eliminated the duplicates, and we’re left with elements in both sets, which is the union of both sets.

If we want to get the set difference between two Sets, we can convert one Set into an array and then use the filter function on it to exclude the elements from the other Set. For example, we can write:

let set1 = new Set();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

let set2 = new Set();
set2.add(1);
set2.add(2);
set2.add(7);
set2.add(8);

const differenceBetweenSet1and2 = new Set([...set1]
  .filter(item => !set2.has(item)))
console.log(differenceBetweenSet1and2);

When we log the value of differenceBetweenSet1and2, we should get[3,4] because we converted set1 into an array with the spread operator and called the filter on it. In the callback function of filter we returned !set2.has(item) to exclude the elements from set2 that are also in set1 , so we’re left with the elements that are only in set1.

To get the symmetric difference between two Sets, i.e., the set of elements that are only in one Set or the other, we can get the intersection between two Sets and then exclude the elements that are in the intersection. For example, we can write the following:

let set1 = new Set();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

let set2 = new Set();
set2.add(1);
set2.add(2);
set2.add(7);
set2.add(8);

const intersectionBetweenSet1and2 = new Set(
  [...set1]
    .filter(item => set2.has(item))
)

const symDiffBetweenSet1and2 = new Set(
  [...set1,...set2]
    .filter(item => !intersectionBetweenSet1and2.has(item))
)

console.log(symDiffBetweenSet1and2);

In the code above, we obtained the intersection between set1 and set2. Once we got intersectionBetweenSet1and2, we put everything in set1 and set2 in the same array by using the spread operator, then called filter on that array and returned !intersectionBetweenSet1and2.has(item) in the callback function to exclude the elements that are in the intersection. This is what we want to eliminate from the array to get the symmetric difference. Then, we just convert the result back to a Set with the Set constructor. At the end, when we log symDiffBetweenSet1and2, we should get [3,4,7,8] which are elements that are only in one Set or the other.

To check if an element is a Superset of another set, we can once again convert it to an array and use that to check. For example, if we have:

let superSet = new Set();
superSet.add(1);
superSet.add(2);
superSet.add(3);
superSet.add(4);

let set = new Set();
set.add(1);
set.add(2);

const isSuperset = [...set].every(item => superSet.has(item));
console.log(isSuperset);

In the code above, we convert set to an array and then check if every element of set is included in the Superset with the has function. The every method is an array method that checks if every element in an array meets a specified condition.

We can also create Set objects from strings. We can pass a string straight into the Set constructor. The result would be a Set that has the individual characters of the string with the duplicate entries removed. For example, if we have the following code:

const letterSet = new Set('element');

Then we get back {“e”, “l”, “m”, “n”, “t”} when we run console.log(letterSet). Note that if there are duplicates, the characters that are inserted later which are the same as any existing characters will be omitted, so the one that is inserted earlier stays.

JavaScript Sets is a useful data structure that models the properties of mathematical sets. Sets can be converted into arrays, so we can manipulate them as arrays and then turn them back into Sets. This is very handy for working on them, since Sets do not have as many methods as arrays have.

Categories
JavaScript Answers

How to Create an Empty Array of a Given Size with JavaScript?

Sometimes, we want to create an empty array of a given size with JavaScript.

In this article, we’ll look at how to create an empty array of a given size with JavaScript.

Create an Empty Array of a Given Size with JavaScript

To create an empty array of a given size with JavaScript, we can use the Array constructor.

For instance, we can write:

const arr = new Array(5);  
console.log(arr.length)

to create an empty array with length 5 by passing in the length as the argument for the Array constructor.

Therefore, arr.length is 5 according to the console log.

Conclusion

To create an empty array of a given size with JavaScript, we can use the Array constructor.

Categories
JavaScript Answers

How to Assign Multiple Variables to the Same Value with JavaScript?

Sometimes, we want to assign multiple variables to the same value with JavaScript.

In this article, we’ll look at how to assign multiple variables to the same value with JavaScript.

Assign Multiple Variables to the Same Value with JavaScript

To assign multiple variables to the same value with JavaScript, we can use the destructuring syntax.

For instance, we can write:

const [
  moveUp,
  moveDown,
  moveLeft,
  moveRight,
  mouseDown,
  touchDown
] = Array(6).fill(false);

console.log(
  moveUp,
  moveDown,
  moveLeft,
  moveRight,
  mouseDown,
  touchDown
);

to destructure the values of the array that we created with Array(6).fill(false) .

Then we assign each value in the array to each variable on the left side.

Therefore, from the console log, we can see:

false false false false false false

logged.

Conclusion

To assign multiple variables to the same value with JavaScript, we can use the destructuring syntax.