I have the following code...
spa.factory("linkService", function() {
var currentLink = null;
return {currentLink:};
});
var cssController = spa.controller("cssController", function(linkService, currentLink) {
this.fileName = linkService.currentLink;
});
var navigationController = spa.controller("navigationController", function(linkService, currentLink) {
this.setLink = function(setValue) {
linkService.currentLink = setValue;
};
this.checkCurrent = function(checkValue) {
return linkService.currentLink == checkValue;
}
});
I've created this code from a snippet I wrote in another question, and fixed the things I was told were wrong with my first attempt. That question can be found here. This is a more specific case, and is therefore not a duplicate.
After checking the console, I believe the problem with this script lies in the factory.
The attempted function of the linkService factory is to provide a variable, currentLink which can be accessed and changed dynamically by more than one controller. The variable inside the factory I believe should be accessed by injecting the factory as a dependency into the controller function, as well as the variable.
What is the issue here?
Your linkService factory returns an object with the slot 'currentLink' and its value undefined.
You have to return the variable directly or you can return an object which references your variable or you can return an object which includes getter and setters to your variables.
The last variant has the advantage of having a nice interface defined in place.
Your code will be better readable.
spa.factory("linkService", function() {
var currentLink = "/myLink.html";
/* accessor for currentLink */
var getLink = function(){
return currentLink;
};
return {get: getLink}; // service interface
});
--- update
Some more details:
currentLink is the variable which should be accessed and which is present in the context of the linkService only
the factory returns the object "{get: getLink}" as the service. So if a controller injects the linkService, it gets this object.
Using linkService.get(); you can access the variable currentLink.
getLink is a local function only. It serves as an accessor.
The factory should return objects/methods as such:
spa.factory("linkService", function() {
var linkServiceFactory = {};
var _currentLink = null;
linkServiceFactory.currentLink = _currentLink;
return linkServiceFactory;
});
In the controller to inject it with the factory name to get its sub-parts.:
var cssController = spa.controller("cssController", function(linkService) {
this.fileName = linkService.currentLink;
});
Similarly,
var navigationController = spa.controller("navigationController", function(linkService) {
// other code.
});
Related
Im doing a course in frontend Dev in uni and the teacher insists on us using a old book so to learn the history and basics of JavaScript before we move on to more advanced and recent implementations.
Now in this book we are instructed to code a webpage for a food truck and it is supposed to take orders.
Now in some scripts the objects are defined like this :
function DataStore() {
this.data = {};
}
Here the data object is defined using the keyword "this" as in saying it belongs to the function object DataStore.
however in some scripts the data object is defined as:
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
My question is what is the difference in the two data objects?
Short answer is at the bottom
Long and boring introduction to how things work
When you write this :
function SomeThing() { }
You can always do
let a = new SomeThing();
even when it doesn't make sense like in :
function lel() { console.log('lelelel'); }
let g = new lel();
console.log(g);
console.log(g.constructor.name);
What this means is that classes are actually the same as functions. And a function in which you use the keyword this usually means you will want to create instances of it.
now if I want all instances of my lel() function class to have a property called foo and a method called bar here's how you do :
lel.prototype.foo = "Some initial value";
lel.prototype.bar = function() {
console.log(this.foo);
}
now I can do
let g = new lel();
lel.bar();
lel.foo = "Hell yeah !";
lel.bar();
In conclusion, this :
function SomeThing() {
this.data = {};
}
SomeThing.prototype.setData = function(key, value) {
this.data[key] = value;
}
SomeThing.prototype.getDataKeys = function() {
return Object.keys(this.data);
}
SomeThing.prototype.getDataValues = function() {
return Object.values(this.data);
}
is the same thing as this
class SomeThing {
constructor() {
this.data = {};
}
setData(key, value) {
this.data[key] = value;
}
getDataKeys() {
return Object.keys(this.data);
}
getDataValues() {
return Object.values(this.data);
}
}
Clarifications about your question
If somewhere in your code you have :
FormHandler.prototype.addSubmitHandler = function() {
console.log('Setting submit handler for form');
this.$formElement.on('submit', function(event){
event.preventDefault();
var data = {};
if necessarily means that somewhere else in your code you have
function FormHandler(...) { ... }
Short answer
This :
function DataStore() {
this.data = {};
}
is how you define a class named DataStore with a property called data initialized to the value {}
And this :
FormHandler.prototype.addSubmitHandler = function() {
...
var data = {};
}
is how you add a method called addSubmitHandler to the already defined class FormHandler. That method uses a local variable called data, could have been any other name
In the first case, data is a property of the object that is created like this: new DataStore.
You can access this property like this:
var obj = new DataStore();
obj.data // => {}
/* or */
obj['data'] // => {}
In the second case, data is just a global variable, inside of an event handler, that is added executing the function.
var obj = new FormHandler();
obj.addSubmitHandler();
You access this variable like this:
data // => {}
I don't think it's a good idea to learn old JS. You would be out of date. You wouldn't be able to use latest technologies, and it would be harder to get a job.
If I have some base factory that has a bunch of methods I want to extend to a bunch of other factories such as
function TestFactory() {
var service = {};
service.name = null
service.lastname = null
service.screech = function() {
alert(service.name + service.lastname)
}
return service;
}
And I want to extend that functionality to another service such as
function NewFactory() {
var service = angular.copy(TestFactory)
service.name = 'Cool'
service.lastname = 'Guy'
return service;
}
I would expect NewFactory.screech() to alert "CoolGuy", but it appears it is calling the screech method in the scope of the original TestFactory where name and lastname are null.
How can I accomplish this pattern?
I have also tried using angular.extend but had the same result.
Change service to this inside the definition of service.screech:
service.screech = function() {
alert(this.name + this.lastname)
}
It didn't work because when you referred to service inside the function, due to closure, service was hard-coded to the service object at the time of definition. The reference was not updated when you made the copy. this, on the other hand, is dynamic and always refers the the object that the function is being called on, e.g. with service.screech().
Also, you need to set service to a copy of the object resulting from the TestFactory, not to a copy of the TestFactory itself:
var service = angular.copy(TestFactory())
Change service variable to this. Closure will bind the service variable to the function instead service should be using scope of the object so that it can be inherited.
All functions inside the factory should be using this to refer the object.
function TestFactory() {
var service = {};
service.name = null
service.lastname = null
service.screech = function() {
alert(this.name + this.lastname)
}
return service;
}
Also change the following code to return the factory object not the Factory Function
function NewFactory() {
var service = angular.copy(TestFactory())
service.name = 'Cool'
service.lastname = 'Guy'
return service;
}
I have the function structured this way because I need to inject it as a angularjs Factory. however, when I use it stand along to create a test for it, I encounter difficutly. I can NOT reference the ItemModel inside the ItemModelGenerator! I can not create an instance of it by using it as a constructor! I tried many many ways use keyword of new or invoke both, invoke either, pass arguments in bot or either, none of them works. I am confused...
Is this possible to somehow use this ItemModelGenerator as a constructor for another var? or, let say use the ItemModel inside it to generate, but in a condition that of course, the var has to be outside of ItemModelGenerator, because it is a factory.
I tried:
var Service = new ItemModelGenerator();
Service.ItemModel();
new ItemModelGenerator().ItemMode();
new ItemModelGenerator.ItemMode();
..etc
BTW, it does work as a angularjs factory injection, its tested.
Thanks
'use strict';
function ItemModelGenerator() {
function ItemModel(inputItem) {
var defaults = {
id:'na',
name:'na'
};
var location = inputItem ? inputItem : { defaults };
this.id = location.id;
this.name = location.itemName ? location.itemName : location.name;
this.itemIsReal = this.isReal(this.id);
}
ItemModel.prototype.isReal = function(id) {
return id !== false ? true : false;
};
return ItemModel;
}
You are returning ItemModel from ItemModelGenerator when you call ItemModelGenerator. So what you get back is an ItemModel:
var ItemModel = ItemModelGenerator();
var instance = new ItemModel();
alert(instance.name);
You are returning the constructor function as the result of your wrapping function. Try:
var Service = new ItemModelGenerator()();
I am trying to make a parent data access layer class that is inherited by multiple classes.
parent class:
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id); //doesnt work
}
}
Child Class:
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
Now in my main class:
var aJob = new Job();
aJob.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..
As you can see, I need to create a parent function with shared variables such as ID, so when I inherit the parent class, I can assign values to these variables so the shared logic of hte parents class work, then my extended class's can have specific logic
You can start with construction like this:
var DataAccess = function() {
this.Save = function(){
console.log('DataAccess Save call', this.ListName, this.Id);
}
}
var Job = function(){
this.ListName = 'MyList';
}
Job.prototype = new DataAccess();
/**
* Delete me to use parent's Save method.
*/
Job.prototype.Save = function(){
console.log('Job Save call', this.ListName, this.Id);
}
var aJob = new Job();
aJob.Id = 1;
aJob.Save();
#stivlo described how it works in his answer here: https://stackoverflow.com/a/4778408/1127848
The problem I had was I wanted to reuse the same code. I think I have worked it out this way, im still not 100% its the right way to go with prototype programming :
function DataAccess() {
//setup common variables
}
DataAccess._Save_(listname, id){
commonSaveLogic(id);
doStuff(listname);
}
function Job() {
this.ListName = 'Jobs';
DataAccess.call(this); //call DataAccess Constructor
}
Job.prototype = DataAccess;
Job.prototype.constructor = Job;
Job.ProtoType.Save = function(){
this._Save_(this.ListName, this.Id);
}
function AotherList() {
this.ListName = 'AnotherList';
DataAccess.call(this);
}
//same as above. Job and Another list both inherit off DataAccess.
Dont use .prototype inside the constructor. We define .prototype for sharing same copy to all objects.
You are missing here many things. I'm explaining one by one:
First : SaveLogic(this.Id); //doesnt work
Because You don't use this with the function so it's a global function not a constructor function. And you don't have defined it any where so there will be an error like function SaveLogic not defined
To prevent this error, define the function somewhere.
Second : You have passed this.Id as a parameter. Id using the line aJob.Id = 1; will not be accessible within the SaveLogic(this.Id); because Id is a property of aJob not of ajob.prototype. this.ListName will be available here because it's a property of prototype.
So it you want to get Id inside SaveLogic() function, define it as prototype property.
Third : when this line aJob.Save(); will be invoke it will call
this.Save = function(){
Job.prototype.Save().call(this);
//specific Job Save logic
}
Job.prototype.Save() will search for a function named as Save(). Which is not defined in Job's prototype so function not defined error will occur.
Fourth : call() can not be called anyhow excepts either DataAccess.call() or Job.call();
call() is just like the constructor call excepts it's first parameter get assigned to the constructor's this object.
Here i have improved your code. Just copy and paste it in your editor and see what is going here.
Try this :
function SaveLogic(Id)
{
alert(Id);
}
var DataAccess = function() {
this.Save = function(){
alert(this.ListName); //works
SaveLogic(this.Id);
return this; //doesnt work
}
this.call = function() {
alert('call is called here');
}
}
var Job = function(){
Job.prototype.ListName = 'MyList'; //works
this.Save = function(){
//console.log(Job.prototype.Save());
Job.prototype.Save().call(this);
//specific Job Save logic
}
}
Job.prototype = new DataAccess();
var aJob = new Job();
Job.prototype.Id = 1;
aJob.Save(); //Does not work. Prototype can not see aJob.Id..
I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives between the public interface and the internals. However I keep running into a situation which makes me wonder if my overall usage pattern is correct, or if I should use some variant of the pattern.
The problem is when something passed into the init function of a module and stored privately for internal use also needs to be publicly exposed, either in a Knockout binding expression or some other module. The return statement of the module executes immediately and sometime later the init function is called, typically being passed some dynamic parameters such as Ajax URLs or raw JSON rendered in a script block within a Razor view. Because the module's return statement just returns a copy of the private variable rather than a reference, my setting that private variable in the init function can’t change what has already been returned.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
My workaround is just to wrap objects such as “urls” in a function and then access them via productsModule.getUrls(). However that becomes very messy, especially if the variable is a Knockout observable which is itself a function, and hence to evaluate it I need to use double brackets like productsModule.getMyObservable()().
Is there a nicer way to get at the up-to-date internal values using something which at least approximates the revealing module pattern?
Basic types are passed by value while objects are passed by reference; you could exploit this so that instead over overwriting urls in productsModule you just update it. This way the reference returned in the initial module invocation remains up to date. I've updated your code to show what I mean.
var productsModule = function() {
var urls = {};
var init = function(ajaxUrls) {
// Merge properties into the original object instead; more robust approach
// may be needed
for ( name in ajaxUrls ) {
if (ajaxUrls.hasOwnProperty(name)) {
urls[name] = ajaxUrls[name];
}
}
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Although I don't completely like the idea of having to iterate through all the possible levels of my objects to merge them like that, El Yobo's answer got me thinking about making the result of the module function itself a local variable whose properties I could update.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
result.urls = urls;
};
var result = {
init: init,
urls: urls
};
return result;
}();
// Before init
alert(productsModule.urls); // undefined
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
alert(productsModule.urls.getProduct); // /Product/
Why don't you make urls an observable property ?
Look at my example:
http://jsfiddle.net/Razaz/zkXYC/1/
var productsModule = function() {
var urls=ko.observable();
var init = function(ajaxUrls) {
urls(ajaxUrls);
};
return {
init: init,
urls: urls,
getUrls: function() { return urls(); }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls()); // undefined
alert(productsModule.getUrls()); // object
};
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Greetings.