I have a controller (called searchCtrl) that does a request to a service and then inserts the data from that service into a scope called movieList.
I then display the content of the scope movieList through a ng-repeat in a template,
%li.search_results{"ng-repeat" => "movie in movieList'"}
.addmovie{"ng-click" => "addMovie()"}
%span
Add Movie
%span.title
{{ movie.original_title }}
In this template I call a function called addMovie() which creates a record in my database.
The issue here is that I want to seperate my search function and addMovie function in different controllers. That means that the addMovie() function is in a controller called addMovies.
So when I click on the .addmovie div and fire the addMovie() function, it doesn't do anything. So I'm wondering if it is possible to make a connection to the addMovie() function inside addMovies controller through the searchCtrl controller.
You need to move the addMovie() function into a service. That way any controller can access it just by injecting the service into the controller.
app.service("movieService",function() {
this.addMovie = function() {
//stuff
}
});
Then you would inject the service into your controller like this:
app.controller("searchCtrl",function($scope, movieService) {
//call it here
movieService.addMovie();
});
Related
I have an angular component that is reused multiple time in the same page.
The angular component is dependent on a service, since it is reused multiple times, I would like to have a new instance of a service for each component, is that possible? Or do I have to use a for loop and create a separate object inside the service for each component to achieve the same effect?
Edit: I am using angular 1
You can create a factory (instead of a service) which returns a function to which you can even provide some data (think of it as a constructor).
angular
.module('app')
.factory('MyFactory', MyFactory);
function MyFactory() {
return (someOptions) => ({
myProperty: someOptions.myProperty,
myMethod: () => {
// ...
}
});
}
You can than use it in your controller like so. Every time you call MyFactory({ ... }) a new separate "instance" will be created.
angular
.module('app')
.controller('MyController', MyController);
function MyController(MyFactory) {
const myFactoryObj = MyFactory({ myProperty: 'test' });
}
You can use that service in each of your components as DI and then call that service to create a new instance every time. You can also set 'cache':true in your function so that you don't make multiple api calls for the same data. (Only for 'GET' method). Does that clarify your doubt?
I am doing an app where when I click on a marker on a google.map triggers some action, specifically I want to get an object out of an array of objects to display the details of such object.
I use the controller defs like so
(function() {
'use strict';
angular
.module('gulpAngular')
.controller('GeolocationController', GeolocationController);
/** #ngInject */
function GeolocationController(HouseList) {
....
}
})();
The HouseList is a service defined elsewhere and having a method called getHouses()
Inside my controller, I do besides other things this:
var vm = this;
vm.houses = HouseList.getHouses();
Then I define my marker on the map like
allMarkers = new google.maps.Marker({....});
and add an Listener to it like below. To make things simple, I assign vm.house = vm.houses[0]
allMarkers.addListener('click', function() {
vm.house = vm.houses[0]
}
Now I suppose I should be able to use the vm.house object to display in my html block the attributes of this house object in the fashion of
<h4>{{vm.house.bedrooms}}</h4>
HOWEVER, NOTHING GETS DISPLAYED. I should see my vm.house object be updated and this reflected on the DOM, correct? What do I miss?
Funny: When i add a simple button on the html and use a ng-click function on it without anything other than say console.log(vm.house), not only it does display the correct object, but also the refresh of the html is happening. I am lost
thanks
Peter
addListener is not an Angular function and will not trigger the digest loop. You need to do it manually.
For example:
allMarkers.addListener('click', function() {
$scope.$apply(function () {
vm.house = vm.houses[0]
});
});
Note that you need to inject $scope for this.
ng-click triggers the digest loop, which is why using it will update the HTML.
I have one controller.
app.controller('first',['$scope','scopeService', function ($scope,scopeService){
$scope.initialize = function()
{
scopeService.store('value', $scope);
}
}]);
My second controller is
app.controller('second',['$scope','scopeService', function ($scope,scopeService){
$scope.initialize = function()
{
scopeService.get('value', $scope);
}
}]);
But my second controller is loaded before first so i am getting value as undefined..
You can pass data between the controller in two different ways. One way is to use a service to get and store data. Then both controllers can get the data from the service itself. Services are singleton so if it stores data once in its variable then another controller can get is as well.
Another way is to use Angular events. You can emit an event from your second controller and have the first controller listen for the event.
Example code, emit event:
$scope.$emit('event-name', {data: someDate});
Then receive the event using $rootScope:
$rootScope.$on('event-name', function (event, data) {
//do something with data
});
In your case, you should emit the event when your controller receives the data. Then the first controller listening to this event will get the data as well.
I have the following controllers:
HeaderCtrl, NewsFeedCtrl, MainCtrl
MainCtrl contains both the other two controllers, which are in the same level.
I'm defining an object in authenticationService and update its value in MainCtrl and I update it frequently in NewsFeedCtrl and I want to display its value in the HTML page controlled by HeaderCtrl.
when I use this line in my HeaderCtrl:
$scope.unreadNum=authenticationService.notificationList.length;
and then I use data binding in my HTML page to display its value:
{{unreadNum}}
I only get the initial value I inserted in authenticationService, not the one after the update in the other controllers.
it seems that my HeaderCtrl is defining all his scope objects only one time and then there's no more use for the Ctrl, but I still want his HTML page to be updated after the update in object values in other controllers.
to sum it up: the value of the object I want is stored in one of my services, and I am unable to display it in my HTML page because I can't seem bind it correctly.
You can send messages between the controllers using a service. The service looks something like this...
aModule.factory('messageService', function ($rootScope) {
var sharedService = {};
sharedService.message = {};
sharedService.prepForBroadcast = function(msg) {
this.message = msg;
this.broadcastItem();
};
sharedService.broadcastItem = function () {
$rootScope.$broadcast('handleBroadcast');
};
return sharedService;
});
In the controller that is sending the message, inject this service...
aModule.controller("sendingController", function ($scope, messageService) {
Then add a method that will broadcast the change to any controller that is listening...
$scope.sendMessage = function (someObject) {
messageService.prepForBroadcast(someObject);
},
In any controller that wants to receive the message, inject the service, and add a handler like this to do something with the message...
$scope.$on('handleBroadcast', function() {
//update what you will..
$scope.something = messageService.message;
});
Within an angular controller I am attaching to a websocket service. When the controllers scope is destroyed I obviously want to remove the subscription.
Is it safe to pass the current scope to my service subscription function so it can auto remove on scope destroy? If I dont then each controller who attaches to a socket listener has to also remember to clean up.
Basically is it safe to pass current $scope to a service function or is there a better way of doing this?
I had similar need in my project. Below is the object returned in a AngularJS factory (which initializes WebSocket). The onmessage method automatically unsubscribes a callback if you pass in its associated scope in the second argument.
io =
onmessage: (callback, scope) ->
listeners.push callback
if scope then scope.$on "$destroy", => #offmessage callback
offmessage: (callback) -> listeners.remove callback
The JavaScript equivalence is below.
var io = {
onmessage: function(callback, scope) {
var _this = this;
listeners.push(callback);
if (scope) {
scope.$on("$destroy", function() {
_this.offmessage(callback);
});
}
},
offmessage: function(callback) {
listeners.remove(callback);
}
};
I would not pass the scope. Instead, I would explicitly, in your controller, hook up the unsubscribe.
From http://odetocode.com/blogs/scott/archive/2013/07/16/angularjs-listening-for-destroy.aspx :
$scope.$on("$destroy", function() {
if (timer) {
$timeout.cancel(timer);
}
});
I think having this done explicitly is not as magical, and easier to follow the logic. I think the service would be doing too much if it were to also unsubscribe. What if a controller wants to unsubscribe early?
However, if you do have a very specific use case that's used everywhere, it would be fine to pass the scope in. The amount of time the service needs the scope is very small, basically when the controller first executes so that the service can listen to the $destroy event.