I tried this with no luck:
app.controller('PageLayoutController', function ($scope)
{
// Scope properties
$scope.PageMap = {};
// Constructor
function PageLayoutController() {
alert( "contructing" );
}
return PageLayoutController;
});
I'm looking for a default or popular way of defining the construct of these controllers in angular.
I'm aware i can just create a function called Construct and then call it first, but i wondered if there was an official way of doing it?
I assume you may want to invoke the defined function during Controller getting instantiated. If that's the requirement, you can follow the following syntax.
angular.module('myApp', [])
.controller('PageLayoutController', '$scope', function($scope) {
// Scope properties
$scope.PageMap = {};
$scope.PageLayoutController = function() {
// Do stuffs here
};
// Call the function when the Controller get first invoked
$scope.PageLayoutController();
});
Also you can listen into the $routeChangeStart event and call the function as well.
$scope.$on('$routeChangeStart', function(next, current) {
... you could trigger something here ...
});
Also you can use any of the following events as well.
$routeChangeSuccess
$routeChangeError
The controller function is already a constructor so anything you write in the its body will be executed on construction.
Not quite sure what you are exactly trying to do. But being specific, angular instantiates the controller constructor with new operator when it is needed. So what you are trying to do is more of javascript specific question than angular specific. It does it as:
new ctor(); //or new ctor;
had it been new (ctor()) your code will work, but that is not how it happens obviously. The function reference passed in is newed up, not the result of the function execution. So in your case if you were to do this then you need to return the newed up instance. i.e
return new PageLayoutController;
Example
Related
I haven't understand the function definition inside a method in javascript.
For example in AngularJS I have th code:
sth.controller('ctrlname', function ($scope, $ionicModal, par3, par4){
//code
});
I also have th code:
var f = function (par5,par6){
return par5 + par6;
}
If I call f(2,3) I get the result 5.
So in controller and other similar examples I choose arbitrary names for the parameters inside function or variables that exists previously?
As #MikeFeltman said, you can use any name for your functions' arguments
BUT
Angular as its own logic for dependency injection and it can use argument's name to identify which piece of software your controller/service/etc depends on.
Let's create a B controller that depends on a A service:
angular.module("testModule",[])
.service("A",function(){
//do stuff
})
.controller("B",function(A){
//do other stuff
});
Angular injector, will look at the B constructor's arguments (here A) and try to find the expected service.
But you can name your arguments as you want :
angular.module("testModule",[])
.service("A",function(){
//do stuff
})
.controller("B",["A",function(dontCareAboutVarName){
//do other stuff
}]);
Here the injector, won't look at the function's arguments as it will find an array describing the dependencies and, the last item will be the controller constructor.
Please, take a look at the documentation about angular's injector
The parameters are new variables from within the functions, regardless of it they exist already or not, but I would not use the same names as variables that are available from the containing function in order to avoid confusion. I'd recommend reading up on closures in JavaScript to get a better understanding of this. This is a pretty decent read on them: http://javascriptissexy.com/understand-javascript-closures-with-ease/.
You can define a function in controller like this ..
sth.controller('ctrlname', function ($scope, $ionicModal, par3, par4){
//function...
$scope.sum = function(par3,par4){
return par3 + par4 ;
}
});
$I have a custom javascript object, that can fire events.
I would like to access the angular $scope inside the event-handler, but I have read somewhere that using angular.element(...).scope() is not good, because it's only meant for testing.
My other idea was to register the handle on my object inside the controller, but this is not working (looks like $scope.somevalue gets set, but I don't think $scope is the same object).
I have found many answers here on Stack Overflow for similar questions, but they all seem to be using directives. All I want is to get a value from the object when it's updated, and display it.
Here are the two ways I have tried.
var myObj = GetMyObjInstance();
// Working, but apparently it's not good practise to call .scope() on an element.
myObj.onUpdated = function(){
console.log("myObj updated");
var v = myObj.getValue();
var controllerDiv = document.getElementById("controller");
var $scope = angular.element(controllerDiv).scope();
$scope.apply(function(){
$scope.someValue = v;
});
}
// Tried to do this, thinking i would get closure on the scope.
angular.module('myApp', []).controller('controller', function($scope){
myObj.onUpdated = function(){
console.log("myObj updated"); // Gets logged to console...
var v = myObj.getValue();
$scope.somevalue = v; // ... but somevalue does not get displayed.
$scope.apply(); // Error, says it's not a function, so maybe this is not the right object?.
}
});
Use AngularJS directives to handle events and update scope.
app.directive("xdEvent", function() {
return linkFn(scope, elem, attrs) {
elem.on("event", function(e) {
scope.$eval(attrs.xdEvent, {$event: e});
scope.$apply();
});
};
};
USAGE
<div xd-event="fn($event)"></div>
I think using a Service instead of a controller is a better practice. You can call a service from outside javascript with the injector like explained in this thread :
Call angularjs service from simple js code
If it is still important for you to access this variables from controller, you can use $watch to tell your controller to update itself when the service variables change.
Hope this help.
A+
I would really appreciate some feed back on how this works? I have a service in which I store some session specific variables such as table sorting choices and more.
The code seems to work fine. However, my question is - how is it possible for me to retrieve these values without returning the actual variable?
Shouldn't I have to use some kind of Getter function? Are they made public some way with the setter method, or am I doing something completely wrong here? Is using this some kind of culprit? Or simply my lack of understanding of javascript scoping? :)
Service code:
angular.module('myApp').service('sessionService', function () {
this.searchView = 2; // <-- edited in, forgot this
return {
setSearchView: setSearchView
};
function setSearchView (searchView) {
this.searchView = searchView;
}
});
And then we have the controller.
angular.module('myApp').controller('SearchCtrl', function (sessionService) {
console.log(sessionService.searchView); //undefined
sessionService.setSearchView(1);
console.log(sessionService.searchView); // 1
});
Once I've set for example the searchView from the controller, it is possible to just access it as below.
Anything that can help me understand this would be appreciated.
EDIT: I forgot to add that this.searchView was actually there form the start, same result in console.log in the controller though.
Service are what are called 'singletons' meaning you can set a variable not directly accessible or returned and it will maintain it's values for the life if the UI. In this case, if you want t be able to access sessionService.searchView, you can do it a few ways:
1) Set a private var searchView and then add a getter function to your return statement:
return {
setSearchView: setSearchView,
getSearchView: function() {
return searchView;
}
};
2) create the same private variable and then add it to your return statement:
var searchView;
return {
setSearchView: setSearchView,
searchView: searchView
};
When you inject the service into the controller
angular.module('myApp').controller('SearchCtrl', function (sessionService) {
you are provided with an instance of the service definition function. In other words, your sessionService is basically
new function () {
return {
setSearchView: setSearchView
};
function setSearchView (searchView) {
this.searchView = searchView;
}
}
i.e the function you passed in when you defined the service preceded by new. The new means that you are just using it as a constructor function.
Now, what do we know about new and Javascript constructors - just that if the constructor function returns an object, that's what the left hand side of new is set to. And this in the member methods basically refers to that same object.
In short, your service definition is a constructor function. In plain Javascript it would look something like this.
function SessionService () {
return {
setSearchView: function (searchView) {
this.searchView = searchView;
}
};
}
var sessionService = new SessionService();
Notice that I capitalized SessionService to indicate that it is a constructor and sessionService is in camel case because it is an instance.
With this in mind, when you do
sessionService.setSearchView(1);
you are setting the searchView property of the sessionService instance to 1. And when you do
sessionService.searchView
this is the exact same property that you are accessing and you get the value you set.
You could also do sessionService.searchView = 1 and it would work as well, since all you are doing is working on the sessionService instance.
I am trying to get songs from soundcloud, I am using some input to set value and send it to my factory to get all the related list of songs and display it.
The issue is the the first time all works correctly, but when I am trying to input new values I am getting same results as first time.
My code looks like:
.controller('DashCtrl', function ($scope, SongsService) {
$scope.formData = {};
$scope.searchSong = function () {
SongsService.setData($scope.formData.songName);
};
UPDATE
the factory :
.factory('SongsService', function ($rootScope) {
var List = {};
List.setData = function (tracks) {
var page_size = 6;
SC.get('/tracks', {limit: page_size, linked_partitioning: 1}, function (tracks) {
// page through results, 100 at a time
List = tracks;
$rootScope.$broadcast('event:ItemsReceived');
});
};
List.getItems = function () {
return List;
};
return List;
}).value('version', '0.1');
Thanks for help!
It's hard to tell without a plunkr reproducing the issue and showing all your relevant code, but I think your problem is that you're overwriting the List variable in the async answer, and this List (I assume) is the object you originally returned from your factory.
I see two noteworthy concepts here:
the fact that angular factories are effectively singletons
and that javascript objects are passed by reference-by-value (see call-by-sharing, or one of many stackoverflow discussions).
An angular factory is a singleton, meaning the factory function will only be called once, before the first injection, and every controller it's injected into will work with the same object reference it returned. If you overwrite this object reference, well, the previous value (which the controller has) is still a reference to the original object.
Edit: In fact, by overwriting List you're creating a new object which doesn't even have a setData method anymore!
You probably want to make List private to SongsService, and return a more complex object from the factory that captures List in a closure, and offers some public getter/setter methods for it. (If you insist on replacing the contents of the returned List variable, empty the object and extend it with the new properties - including this method again. But this is much more work, and not a nice solution.)
In Angular Service constructors and Factory methods are singleton objects. You need to return a method that you can call. Your code examples are incomplete so it is hard to tell what is going on. What is returned by your factory method, the List object?
If so, when the first call is completed, it overwrites the List object so that the setData method can't be called a second time. What is the SC object, I can not see in your example how you are injecting it. You probably want to fix that too.
Consider this possible solution.
Service
Songs.$inject = ['$http'];
function Songs($http) {
this.$http = $http;
}
Songs.prototype.getSongs = function(searchTerm) {
return this.$http.get('http://someendpoint/songs', {searchTerm: searchTerm});
}
service('songs', Songs);
Controller
DashController.$inect = ['songs'];
functionDashController(songs) {
this.songs = songs;
this.results = [];
}
DashController.prototype.searchSongs = function(searchTerm) {
var self = this;
this.songs.getSongs(searchTerm).then(function(results) {
this.results = results;
});
}
controller('DashController', DashController);
This is example uses the best practice controllerAs syntax explained here: http://toddmotto.com/digging-into-angulars-controller-as-syntax/
I found the issue,
I got same results all the time because I didnt use cooreclty the api of soundcloud, I didnt send the title on the api... also you are correct, I should not set the list as empty..I should set some value to the list...
EDIT:
Everything is working as I expected. It was just an error calling the template method. I mistyped a () so I was trying template.method instead of template().method;
Anyway, if somebody would like to explain me if this is a valid design pattern or if I should go in a different way I will be definitively very grateful.
I read about the module pattern and I'm trying to implement it in some of my projects. The problem is that, in my opinion, I'm twisting it too much.
I'm inspired by the google apps script style where many objects returns other objects with methods and so on and they pass arguments.
something like
object.method(var).otherMethod();
What I want to achieve is a method that receives a parameter, sets an internal variable to that parameter and then returns an object with methods that uses that variable. Here is a minified version of the code that does not work:
var H_UI =(function (window) {
var selectedTemplate,
compileTemplate = function(){},
parseTemplateFields = function(){};
//template subModule. Collect: collects the template fields and returns a JSON representation.
var template = function(templateString){
if(templateString) selectedTemplate = templateString;
return {
getHtml:function(){ return compileTemplate( parseTemplateFields( selectedTemplate ) ) } ,
collect:function(){
.. operating over selectedTemplate ...
return JSON.stringify(result)}
} };
return {
template:template
};
})(window);
If I remove the line :
if(templateString) selectedTemplate = templateString;
and replace selectedTemplate with the parameter templateString in the methods of the returned object it works as expected. I know that I cant create a set() method in the returned object and use it like this
H_UI.template().set(var)
But I find it ugly. Anyway I think that I'm messing things up.
What is the best way to construct this?
If you want H_UI.template() creates a new object every time you call template() on it, your solution does not work. Because the variable selectedTemplate is created only once when the immediate function is called.
However if your intent is this your solution works fine. (variable selectedTemplate is shared for all calls to template()).
But if you want to every call to template creates a new object. Please tell me to write my idea
Is this a valid design pattern or if I should go in a different way
Yes, enabling chaining is definitely a valid design pattern.
However, if your template() method returns a new object, that object and its methods should only depend on itself (including the local variables and parameters of the template call), but not on anything else like the parent object that template was called on.
So either remove that "global" selectedTemplate thing:
var H_UI = (function () {
function compileTemplate(){}
function parseTemplateFields(){}
// make a template
function template(templateString) {
return {
getHtml: function(){
return compileTemplate(parseTemplateFields(templateString));
},
collect: function(){
// .. operating over templateString ...
return JSON.stringify(result)
}
}
}
return {template:template};
})();
or make only one module with with a global selectedTemplate, a setter for it, and global methods:
var H_UI = (function () {
var selectedTemplate;
function compileTemplate(){}
function parseTemplateFields(){}
return {
template: function(templateString){
if (templateString)
selectedTemplate = templateString;
return this; // for chaining
},
getHtml: function(){
return compileTemplate(parseTemplateFields(selectedTemplate));
},
collect: function(){
// .. operating over selectedTemplate ...
return JSON.stringify(result)}
}
};
})();
The difference is striking when we make two templates with that method:
var templ1 = H_UI.template("a"),
templ2 = H_UI.template("b");
What would you expect them to do? In a functional design, templ1 must not use "b". With the first snippet we have this, and templ1 != templ2. However, if .template() is a mere setter, and every call affects the whole instance (like in the second snippet), we have templ1 == H_UI and templ2 == H_UI.