Reputation: 1621
I'm effectively trying to build a chainable object that contains sub objects or other functions.
It should be used like this:
val().rules.phone("someValue");
So far:
var val = function(){
var validator = function(){
this.fields = [];
return this;
}
validator.prototype = {
addField: function(fieldName){
this.fields.push(fieldName);
return this;
},
rules: {
phone: function(){
//RETURNING THIS DOES NOT RETURN THE PARENT SCOPE
//IT RETURNS SCOPE OF PHONE FUNCTION
return this;
}
}
}
return new validator();
}
I also tried a circular reference via prototype chaining:
var val = function(){
var validator = function(){
this.fields = [];
return this;
}
var rules = function(){
validator.call(this);
}
rules.prototype = Object.create(validator.prototype);
rules.prototype.constructor = rules;
rules.prototype.phone = function(){
console.log('hone');
}
validator.prototype = {
addField: function(fieldName){
this.fields.push(fieldName);
return this;
},
rules: new rules()
}
return new validator();
}
var z = val().rules;
//no 'addFields' function exists on the validator object in the chain.
console.log(z);
Problems:
In the first val().rules.phone()
returns the scope of its function rather then the parent scope. It should return the validator scope.
In the second example, val().rules
DOES have validator as parent on its prototype chain, however addFields
prints undefined, and does not exist in console when tracing the chain.
I know I am over complicating the issue by adding the rules literal. I could just implement chaining with functions directly placed on the prototype object. This is for my own clarification. Is there any other possible way to implement this with the same style usage?
Upvotes: 0
Views: 64
Reputation: 6684
You can get an API like the one you want with this:
var validator = function(){
this.fields = [];
this.rules = new rules(this);
}
validator.prototype = {
addField: function(fieldName){
this.fields.push(fieldName);
return this;
}
};
var rules = function(validator) {
this.validator = validator;
}
rules.prototype = {
addField: function(fieldName) {
this.validator.addField(fieldName);
return this;
},
phone: function() {
console.log("phone");
}
};
v = new validator();
v.rules.addField("hello");
v.rules.phone();
Making rules
inherit validator
is semantically and practically problematic. Your validator.prototype
here:
validator.prototype = {
addField: function(fieldName){
this.fields.push(fieldName);
return this;
},
rules: new rules()
}
will share the same rules
object between all validator
objects, which is probably not what you want. But then if you fixed this, by making a rules
object in the validator
constructor, you would have an infinite loop, since the validator
constructor would call the rules
constructor, and the rules
constructor would call the validator
constructor (since a rules
is a validator
).
Upvotes: 1
Reputation: 18566
var val = function(){
var validator = function(){
this.fields = [];
return this;
}
var rules = function(){
if(!this instanceof rules) return new rules();
validator.call(this);
return this;
}
validator.prototype = {
addField: function(fieldName){
this.fields.push(fieldName);
return this;
},
rules: rules
}
rules.prototype = Object.create(validator.prototype);
rules.prototype.phone = function(){
console.log('hone');
}
return new validator();
}
z = val().rules
actually returns you an object and not a function. that's why you are unable to use prototype
for that.
Upvotes: 1