Custom element inheritance - javascript

I would seem that the lifecycle callbacks fire but I cannot access the mother class properties.
For exemple I have this custom element :
var Game = document.registerElement('x-game', {
prototype: Object.create(HTMLElement.prototype, {
cards: {
value: [],
writable : true,
enumerable : true,
},
createdCallback: {
value: function () {
this.cards = deck();
}
}
})
});
With deck() a function to populate my array.
and I want to create an another element inheriting the former :
var Golf = document.registerElement('x-golf', {
prototype: Object.create(Game.prototype, {
columns: {
value: []
},
waste: {
value: new Waste
},
talon: {
value: new Talon
},
createdCallback: {
value: function () {
Game.prototype.createdCallback.apply();
this.initialize();
}
},
initialize: {
value : function () {
for (var i = 0; i < 7; i++) {
var column = new Column;
for (var r = 0; r < 5; r++){
column.cards[r] = this.cards.pop();
}
this.columns[i] = column;
}
this.waste.cards.push(this.cards.pop());
for (var j = 0; j < this.cards.length; j++){
var card = this.cards.pop();
card.side = 'verso';
this.talon.cards[j] = card;
}
}
})
});
Normally with Game.prototype.createdCallback.apply(); the cards property on a new x-golf element shoud be populated however it is not. The value of the card property on the console is still an empty array, the default value for it.
So How to ensure that the card property will be correctly populated be the call of the superclass createdCallback ?

You're missing a target for the .apply() call:
Game.prototype.createdCallback.apply(this);
Working jsbin.

Related

JavaScript: Why getting last inserted values?

I am getting familiar with the prototype world of JavaScript and this keyword. I am new to Web-world. Today when I started playing with prototype I saw some strange behavior but I am not able to get why this is happening. I've created a constructor Group as following:
// Code goes here
function Group(config) {
this.config = config;
this.getId = function() {
return this.config.id;
};
this.setId = function(id) {
this.config.id = id;
};
}
I use it in one MyGroup constructor like this:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(MyGroup, this.g, myAttrs)
}
addGetterSetter is the function I wrote to add getter and setter dynamically to the attributes of MyGroup.
var GET = 'get',
SET = 'set';
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function addGetterSetter(constructor, target, attrs) {
function addGetter(constructor, target, attr) {
var method = GET + capitalize(attr);
constructor.prototype[method] = function() {
return target[method]();
};
}
function addSetter(constructor, target, attr) {
var method = SET + capitalize(attr);
constructor.prototype[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(constructor, target, attrs[index]);
addSetter(constructor, target, attrs[index]);
}
}
Now when I use MyGroup,Group like this:
var items = [{
id: 123,
name: 'Abc'
}, {
id: 131,
name: 'Bca'
}, {
id: 22,
name: 'bc'
}];
var groups = [];
items.forEach(function(item) {
var g = new MyGroup(item);
groups.push(g);
});
groups.forEach(function(g) {
console.log(g.getId()); //don't know why this logs 22 three times instead of all ids
});
In group.forEach I don't know why the id of the last item is getting logged. I am not able to understand what is going wrong. And how will I be able to get of the group for which g.getId() is invoked. Here is the plunkr
It's because you're adding methods to prototype and you overwrite in the loop each time the previous function so the function hold reference to last object when forEach loop finishes. What you need is to add function to this object:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(this, this.g, myAttrs)
}
function addGetterSetter(object, target, attrs) {
function addGetter(object, target, attr) {
var method = GET + capitalize(attr);
object[method] = function() {
return target[method]();
};
}
function addSetter(object, target, attr) {
var method = SET + capitalize(attr);
object[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(object, target, attrs[index]);
addSetter(object, target, attrs[index]);
}
}
JSFIDDLE

How do I iterate through an instance of this List class in JavaScript

I am trying to iterate over a list var names = new List(); the following way:
var names = new List();
names.append('tom');
names.append('bob');
names.append('marshal');
names.append('Cartman');
names.append('Randy');
for(names.top(); names.currentPosition() < names.length(); names.next()) {
console.log(names.getElement()); // going on and on stuck at one index! infinite loop!!!
}
I am getting an infinite loop with an unchanging index of the list. What
might be going wrong?
Assume the list has already been filled with values using an append method. It is definitely not empty. Here is the implementation of the List class:
function List() {
this.dataStore = [];
this.listSize = 0;
this.position = 0;
}
List.prototype = {
clear: function() {
delete this.dataStore;
this.dataStore = [];
this.position = this.listSize = 0;
},
toString: function() {
return this.dataStore.join(' \n');
},
getElement: function() {
return this.dataStore[this.position];
},
append: function(el) {
this.dataStore[this.listSize++] = el;
},
top: function() {
this.position = 0;
},
bottom: function() {
this.position = this.listSize - 1;
},
prev: function() {
if(this.position > 0) {
this.position--;
}
},
next: function() {
if(this.position < this.listSize - 1) {
this.position++;
}
},
length: function() {
return this.listSize;
},
currentPosition: function() {
return this.position;
},
};
Your next() function won't increment the this.position value past this.listSize - 1 and therefore your conditional portion of the for loop will always evaluate to true since your currentPosition() will always be less than your length().
Take for example, your List having 1 element in it. Here's the for loop values:
names.top() = 0
names.currentPosition() = 0
names.length() = 1
Calling names.next() checks this.position < this.listSize - 1. This can be rewritten: 0 < (1 - 1). So next doesn't increment this.position and your for loop runs infinitely.

Javascript - Looping through classes and adding functions

I'm currently trying to create an HTML5 Canvas game and I want to be able to attach functions to buttons that activate when clicked. I can do this for unique functions but I'm struggling to find a way to do it when looping through many buttons with a predefined function.
I've created an example to show what I've tried so far:
jsFiddle: http://jsfiddle.net/ra1rb74w/1/
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction) {
this.aFunction = newFunction;
},
// Use the current function
useFunction: function () {
if (this.aFunction != null) {
this.aFunction;
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) { console.log(x); }
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction(x));
}
// Use the function in the first class
myClasses[0].useFunction();
You can see that all the functions get triggered which I don't want, and the useFunction() function doesn't work. Is there a way to do this?
So you are triggering baseFunction by calling baseFunction(x). You need to either get baseFunction to return a function which can be executed:
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction) {
this.aFunction = newFunction;
},
// Use the current function
useFunction: function () {
if (typeof this.aFunction === "function") {
this.aFunction.call(this);
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) {
return function() {
console.log(x);
};
}
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction);
}
// Use the function in the first class
myClasses[3].useFunction();
JsFiddle
Or add another parameter to addFunction which can be called like addFunction(baseFunction, x):
// The class that we want to create an array of
myClass = function() {
this.aFunction;
};
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction, value) {
this.aFunction = newFunction;
this.x = value;
},
// Use the current function
useFunction: function () {
if (typeof this.aFunction === "function") {
this.aFunction.call(this, this.x);
}
}
};
// The base function we will use in the classes
var baseFunction = function(x) { console.log(x); }
// Create the array of classes
var myClasses = [];
// Add 10 classes to the array and add a function to each of them
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction, x);
}
// Use the function in the first class
myClasses[3].useFunction();
JsFiddle
Note I also changed your check for aFunction == null as the function passed in may be null, or a string, or anything else. You want to check if it is executable.
Change to
...
myClass.prototype = {
// Add a new function to this class
addFunction: function (newFunction, x) {
this.aFunction = newFunction;
this.aFunctionX = x;
},
useFunction: function () {
if (this.aFunction != null) {
this.aFunction(this.aFunctionX);
}
}
};
...
...
for (var x = 0; x < 10; x++) {
myClasses.push(new myClass());
myClasses[x].addFunction(baseFunction, x);
}
...
Here is a fiddle http://jsfiddle.net/ra1rb74w/6/

Getting a number that represents the level of an object/nested object inside an object

Consider the following Javascript object
var items = [{
content: 'A_lvl0',
}, {
content: 'B_lvl0',
}, {
content: 'C_lvl0',
children: [{
content: 'C_1_lvl1',
}, {
content: 'C_2_lvl1',
children: [{
content: 'C_1_lvl2'
}, {
content: 'C_2_lvl2',
children:[{
content: 'C_1_lvl3'
}, {
content: 'C_2_lvl3'
}]
}]
}, {
content: 'C_3_lvl1'
}]
}];
the lvlx you see in the content property of the object where x represents how deeply the object is nested, suppose i had a reference to an object inside the above object and wanted to return the value of x which is how deeply the object is nested, i know i have to use recursion but i am not sure how to keep track of the top lvl
i was able to print the nested content of all objects using the following function
var scanObj = function (obj) {
for (var i = 0; i < obj.length; i++) {
console.log(obj[i].content);
if (obj[i].hasOwnProperty('children')) {
scanObj(obj[i].children);
}
}
};
but now what i am trying to write is
var getlvlByRef = function (obj,subobject) {
//return lvl
};
var getlvlByPropertyValue = function (obj,propertyname,propertyvalue) {
//return lvl
};
and my problem is i am not sure how to keep track when i reach the last nested lvl, could you please point me to the right way?
here is a fiddle http://jsfiddle.net/eG3qR/
Here, I created a fiddle for my solution
http://jsfiddle.net/3W5qY/3/
function getlvlByPropertyValue(obj, propertyName, propertyValue, level){
if(level == undefined) level = 0;
if(obj == undefined || obj.length == 0) return -1;
for(var i = 0;i < obj.length; i++){
var curObj = obj[i];
if(curObj[propertyName] != undefined && curObj[propertyName] == propertyValue) {
return level;}
if(curObj["children"] != undefined){
var childSearchResult = getlvlByPropertyValue(curObj["children"], propertyName, propertyValue, ++level);
if(childSearchResult > 0) {
return childSearchResult;
}
}
}
return -1;
}
It'll return -1 if not found.
if you wanted scanObj to print out the current level you're at, you could pass the level down to scanObj
so:
var scanObj = function (obj, level, init) {
if (level === undefined || init) {
level = 0;
}
for (var i = 0; i < obj.length; i++) {
console.log(obj[i].content);
console.log(level);
if (obj[i].hasOwnProperty('children')) {
scanObj(obj[i].children, level);
}
}
};
scanObj(myObj, 0, true);
can probably be cleaned up so you don't need the init flag, but this should print the obj content as well as the level that the object is at.

Array doesn't get filled correctly

I have these JavaScript entities: Item and Items.
var exports = {};
exports.Item = function(item) {
if (item) {
for (var attr in this.attributes) {
var value = item[attr];
if (value !== undefined) {
this.attributes[attr] = value;
}
}
}
return this;
};
exports.Item.prototype.attributes = {
_id: "",
title: ""
};
exports.Items = function(items) {
if (items && items.length > 0) {
for (var i = 0; i < items.length; i++) {
this.add(items[i]);
}
}
};
exports.Items.prototype.arr = [];
exports.Items.prototype.add = function(item) {
if (item) {
item = new exports.Item(item);
this.arr.push(item.attributes);
}
};
exports.Items.prototype.toJSON = function() {
var json = [];
for (var i = 0; i < this.arr.length; i++) {
json.push(this.arr[i]);
}
return json;
};
var i1 = new exports.Item({
_id: "1",
title: "1"
});
var i2 = new exports.Item({
_id: "2",
title: "2"
});
var i3 = new exports.Item({
_id: "3",
title: "3"
});
var items = new exports.Items([i1,i2,i3]);
console.log(items.toJSON());
There is a problem which I cannot find. When I execute the following code I get the last item 3 times instead of all the items.
I am sure the mistake is something small I cannot see. Maybe you can help me?
Member variables shouldn't be initialized in the prototype. Prototype variables will be shared across all instances. Instead, define the members in the constructor. So, instead of this:
exports.Items.prototype.arr = [];
Do this:
exports.Items = function(items) {
    this.arr = []; // instance variable
if (items && items.length > 0) {
for (var i = 0; i < items.length; i++) {
this.add(items[i]);
}
}
};

Categories