Iterate over an object with delay - javascript

I am trying to iterate over nested children of an object, but need have a delay after every child. Normally I would just write a recursive function and use that to iterate over an object, but this happens near instantly. How can I do this with a delay?
I thought about saving the index in a variable and accessing children using that, then increasing the index every time a setInterval is run, but how can this be expanded to take nesting into account?
Function to iterate:
function iter(obj) {
for (var i = 0; i < obj.length; i++) {
console.log(obj[i].command);
if (typeof obj[i].contains == "object") {
iter(obj[i].contains);
}
}
}
iter(object);
Example object:
[
{
"command":"do (5)",
"contains":[
{
"command":"move.up()",
"contains":false
},
{
"command":"move.left()",
"contains":false
},
{
"command":"if (kind == \"item\")",
"contains":[
{
"command":"move.down()",
"contains":false
}
]
},
{
"command":"move.right()",
"contains":false
}
]
}
]

First create a flat array from the hierarchy:
function iter(obj) {
var result = [];
for (var i = 0; i < obj.length; i++) {
result.push(obj[i]);
if (typeof obj[i].contains == "object") {
result = result.concat(iter(obj[i].contains));
}
}
return result;
}
var items = iter(object);
Now you can iterate the array with a timer and an index:
var index = 0;
var timer = window.setInterval(function(){
if (index < items.length) {
console.log(items[index].command);
index++;
} else {
window.clearInterval(timer);
}
}, 1000);
Demo:
var object = [
{
"command":"do (5)",
"contains":[
{
"command":"move.up()",
"contains":false
},
{
"command":"move.left()",
"contains":false
},
{
"command":"if (kind == \"item\")",
"contains":[
{
"command":"move.down()",
"contains":false
}
]
},
{
"command":"move.right()",
"contains":false
}
]
}
];
function iter(obj) {
var result = [];
for (var i = 0; i < obj.length; i++) {
result.push(obj[i]);
if (typeof obj[i].contains == "object") {
result = result.concat(iter(obj[i].contains));
}
}
return result;
}
var items = iter(object);
var index = 0;
var timer = window.setInterval(function(){
if (index < items.length) {
log(items[index].command);
index++;
} else {
window.clearInterval(timer);
}
}, 1000);
function log(str) {
document.getElementById('log').innerHTML += str + '<br>';
}
<div id="log"></div>

Related

Get index of array is not working

I am learning Vue and I am trying to access a string in an array by it's index, but I always get an error when trying to read the string. Here's my code:
var vm = new Vue({
el: '#top',
data: {
Cars: [],
DefaultCarList: [],
AddedCars: [],
SelectedCar: ''
},
methods: {
addCar: function(car) {
var addedCarCount = this.AddedCars.length;
var defaultCarCount = this.DefaultCarList.length;
var containsCar = function () {
for (var i = 0; i < addedCarCount; i++)
{
if (this.AddedCars[i] === car) // error here
{
return true;
}
}
return false;
}
var carIsValid = function() {
for(var i = 0; i < defaultCarCount; i++)
{
if(this.DefaultCarList[i] === this.SelectedCar) // error here
{
return true;
}
}
return false;
}
if (containsCar() === false && carIsValid){
this.AddedCars.push(car);
}
}
}
})
HTML:
<label for="carsId">Cars</label>
<select id="carsId" name="cars" v-model="SelectedCar">
<option disabled value="">Select</option>
<option v-for="car in DefaultCarList" :value="flavor">{{car}}</option>
</select>
<div>
<button type="button" class="hollow button success small"
v-on:click="addCar(SelectedCar)">Add Flavor</button>
</div>
Is it valid to iterate over an array like this in Vue and access the property by it's index? What is the correct way to do this?
Problem is with 'this' keyword it uses inner this where it doesn't have DefaultCarList variable, should use () => {} syntax .Error in this code
var carIsValid = function() {
for(var i = 0; i < defaultCarCount; i++)
{
if(this.DefaultCarList[i] === this.SelectedCar) // error here
{
return true;
}
}
return false;
}
should be
var carIsValid = () => {
for(var i = 0; i < defaultCarCount; i++)
{
if(this.DefaultCarList[i] === this.SelectedCar) // error here
{
return true;
}
}
return false;
}
and
var containsCar = () => {
for (var i = 0; i < addedCarCount; i++)
{
if (this.AddedCars[i] === car) // error here
{
return true;
}
}
return false;
}
The problem is that this it's not a reference to your model.
In your example this is a reference to window object.
Have a look here in order to understand the scope of this keyword in javascript.
You should use arrow functions.
var containsCar = () => {
for (var i = 0; i < addedCarCount; i++)
{
if (this.AddedCars[i] === car) // error here
{
return true;
}
}
return false;
}
or you could just define a self variable.
var self=this;
var containsCar = function() {
for (var i = 0; i < addedCarCount; i++)
{
if (self.AddedCars[i] === car) // error here
{
return true;
}
}
return false;
}
Further more, I recommand you to use native javascript functions in order to have a clean code.
var containsCar = function () {
for (var i = 0; i < addedCarCount; i++)
{
if (this.AddedCars[i] === car) // error here
{
return true;
}
}
return false;
}
var carIsValid = function() {
for(var i = 0; i < defaultCarCount; i++)
{
if(this.DefaultCarList[i] === this.SelectedCar) // error here
{
return true;
}
}
return false;
}
can be achieved using some method :
The some() method tests whether at-least one element in the array
passes the test implemented by the provided function.
var containsCar = () => {
return this.AddedCars.some(a=>a==car);
}
var carIsValid = () => {
return this.DefaultCarList.some(a=>a === this.SelectedCar);
}

implementing split() method for exercise 4 in Object Oriented Javascript 2n edition

here is the question:
Imagine the String() constructor didn't exist. Create a constructor
function, MyString(), that acts like String() as closely as possible.
You're not allowed to use any built-in string methods or properties,
and remember that String() doesn't exist. You can use this code to
test your constructor:
I created constructor however I have no clue how to re-create split method, how to implement that functionality.
If you could give an idea how to implement split method, I would be grateful
function MyString(str) {
var thisObj = this;
var innerLength = 0;
this.length;
function updateLength() {
innerLength = 0;
for (var i = 0; str[i] != undefined; i++) {
innerLength++;
thisObj[i] = str[i];
}
thisObj.length = innerLength;
}
updateLength();
this.toString = function() {
return str;
}
this.charAt = function(i) {
if (isNaN(parseInt(i))) {
return this[0]
} else {
return this[i]
}
}
this.concat = function(string) {
str += string;
updateLength();
}
this.slice = function(start, end) {
var slicedString = "";
if (start >= 0 && end >= 00) {
for (start; start < end; start++) {
slicedString += str[start];
}
}
return slicedString;
}
this.reverse = function() {
var arr = str.split("");
arr.reverse();
var reversedString = "",
i;
for (i = 0; i < arr.length; i++) {
reversedString += arr[i];
}
return reversedString;
}
}
var ms = new MyString("Hello, I am a string")
console.log(ms.reverse())
You can convert the string to an array and use Array.prototype and RegExp.prototype methods.
this.split = function(re) {
var arr = Array.prototype.slice.call(this.toString());
if (re === "") {
return arr
}
if (re === " ") {
return arr.filter(function(el) {
return /[^\s]/.test(el)
})
}
if (/RegExp/.test(Object.getPrototypeOf(re).constructor)) {
var regexp = re.source;
return arr.filter(function(el) {
return regexp.indexOf(el) === -1
})
}
}
function MyString(str) {
var thisObj = this;
var innerLength = 0;
this.length;
function updateLength() {
innerLength = 0;
for (var i = 0; str[i] != undefined; i++) {
innerLength++;
thisObj[i] = str[i];
}
thisObj.length = innerLength;
}
updateLength();
this.toString = function() {
return str;
}
this.split = function(re) {
var arr = Array.prototype.slice.call(this.toString());
if (re === "") {
return arr
}
if (re === " ") {
return arr.filter(function(el) {
return /[^\s]/.test(el)
})
}
if (/RegExp/.test(Object.getPrototypeOf(re).constructor)) {
var regexp = re.source;
return arr.filter(function(el) {
return regexp.indexOf(el) === -1
})
}
}
this.charAt = function(i) {
if (isNaN(parseInt(i))) {
return this[0]
} else {
return this[i]
}
}
this.concat = function(string) {
str += string;
updateLength();
}
this.slice = function(start, end) {
var slicedString = "";
if (start >= 0 && end >= 00) {
for (start; start < end; start++) {
slicedString += str[start];
}
}
return slicedString;
}
this.reverse = function() {
var arr = str.split("");
arr.reverse();
var reversedString = "",
i;
for (i = 0; i < arr.length; i++) {
reversedString += arr[i];
}
return reversedString;
}
}
var ms = new MyString("Hello, I am a string")
console.log(ms.split(""), ms.split(" "), ms.split(/l/))
Iterate and search:
MyString.prototype.split = function(splitter){
var tmp="", result = [];
for(var i = 0; i < this.length; i++){
for(var offset = 0; offset < this.length && offset < splitter.length;offset++){
if(this[i+offset] !== splitter[offset]) break;
}
if(offset === splitter.length){
result.push( tmp );
tmp="";
i += offset -1;
}else{
tmp+=this[i];
}
}
result.push(tmp);
return result;
};
So now you can do:
new MyString("testtest").split("t") //['','es','','','es','']
In action

JavaScript: searching for a simple way of returning 'this' instead of 'val=x'

The following function returns val=ret instead of this. It is complicated and not clear:
getElement: function (nodeId) {
var ret = null;
if (nodeId === this._nodeId) {
ret = this;
} else {
for (var i = 0; i < this._selects.length; i++) {
ret = this._selects[i].getElement(nodeId);
if (ret) {
break;
}
}
}
return (ret);
},
Could you suggest an easier way for that? I tried the following, but you can't
do true/false with if(this._pages[i].getElement(nodeId):
getElement: function (nodeId) {
for (var i = 0; i < this._pages.length; i++) {
if(this._pages[i].getElement(nodeId){
return this;
}
}
return null;
},
I think you should return
this._pages[i].getElement(nodeId)
The second is not the same, because the first check is missing. (No need for an else part if a return is in the then part.)
getElement: function (nodeId) {
var i, ret;
if (nodeId === this._nodeId) {
return this;
}
for (i = 0; i < this._selects.length; i++) {
ret = this._selects[i].getElement(nodeId);
if (ret) {
return ret;
}
}
return null;
},

Transform a JSON file?

I have a generated JSON file that I would like to transform. Is there an easy way to transform the "id"/"value" form of this JSON to a proper key/value JSON object, without using any frameworks?
These lines:
"value":"chrome",
"id":"foo"
would convert to:
"foo": "chrome"
Input JSON:
{"row":[
{
"column":[
{
"value":"chrome",
"id":"foo"
},
{
"value":0,
"id":"bar"
},
{
"value":"baz1",
"id":"baz"
},
{
"value":0,
"id":"legacy"
}
]
},
{
"column":[
{
"value":"firefox",
"id":"foo"
},
{
"value":0,
"id":"bar"
},
{
"value":"baz2",
"id":"baz"
},
{
"value":0,
"id":"legacy"
}
]
}
]
}
Desired JSON:
{"row":[
{
"foo":"chrome",
"bar":0,
"baz":"baz1",
"legacy":0
},
{
"foo":"firefox",
"bar":0,
"baz":"baz2",
"legacy":0
}
]
}
Here is the solution:
var result = {"row": []}
for (var i = 0; i < input["row"].length; i++) {
var object = {};
var column = input["row"][i]["column"];
for (var j = 0; j < column.length; j++) {
object[column[j]["id"]] = column[j]["value"];
}
result.row.push(object);
}
console.log(result);
input variable refers to your initial JSON object.
var input = {"row":[
{
"column":[
...
here is my function, i was typing it out allready before ioseb posted his answer so i figured it post it as well, it's linted and everything
function transform(data) {
"use strict";
var x, i, row, column, colNumb, out = {rows : []}, rownum = data.row.length;
for (x = 0; x < rownum; x += 1) {
row = {};
column = data.row[x].column;
colNumb = column.length;
for (i = 0; i < colNumb; i += 1) {
row[column[i].id] = column[i].value;
}
out.rows.push(row);
}
return out;
}

Dyanamic Execution of javascript code

I have the following JavaScript:
var djs = function (ob) {
return {
remove: function () { //removes element
if (is_array(ob)) {
for (var i = 0; i < ob.length; i++)
ob[i].parentNode.removeChild(ob[i]);
} else {
ob.parentNode.removeChild(ob);
}
},
empty: function () { //makes element empty
if (is_array(ob)) {
for (var i = 0; i < ob.length; i++)
ob[i].innerHTML = "";
} else {
ob.innerHTML = ""
}
},
html: function (str) { //gets or sets innerHTML
if (str) {
if (is_array(ob)) {
for (var i = 0; i < ob.length; i++)
ob[i].innerHTML = str;
} else {
ob.innerHTML = str;
}
} else {
if (is_array(ob)) {
for (var i = 0; i < ob.length; i++)
rob += ob[i].innerHTML;
return rob;
} else {
return ob.innerHTML;
}
}
}
}
}
Here every time I am checking whether ob is an array or not and executing code. I want to minimize this, like instead of:
if (is_array(ob)) {
for (var i = 0; i < ob.length; i++)
ob[i].parentNode.removeChild(ob[i]);
} else {
ob.parentNode.removeChild(ob);
}
I want to use a function like, doEval(ob,code,return), in this case,
doEval(ob,"parentNode.removeChild("+ob+")",NULL);
"return" parameter will return if I specify any like innerHTML. Can any one help?
Don't repeat is_array check:
var djs=function(ob) {
if (!is_array(ob)) ob = [ob];
#SHiNKiROU is right of course, but just to provide an example of how to solve your problem with higher-order functions:
function doToAll(ob, callback) {
if(is_array(ob)) {
for (var i = 0; i < ob.length; i++) {
callback(ob[i]);
}
} else {
callback(ob);
}
}
...
remove:function(){ //removes element
doToAll(ob, function(actualOb) { actualOb.parentNode.removeChild(actualOb); });
},
...
But again, use #SHiNKiROU:s answer for this particular case.
Try this:
function doEval(a, b, c) {
if(is_array(a)) {
eval(b);
} else {
eval(c);
}
}
NULL doesn't exist by the way, it is null.

Categories