I have created a plunker that communicates between two different controller in nested views using factory. Below is the url of plunker.
https://plnkr.co/edit/fWA2Xugjbkf3QvHKfTa0?p=preview .
Here is the factory.
routerApp.factory("widgetService",function($state){
var callbackFunctions=[];
var counter=0;
var addWidget=function(name){
callbackFunctions[0](name);
}
var addCallback=function(callback){
if (callbackFunctions.length===0) {
callbackFunctions.push(callback);
}
}
return{
addCallback: addCallback,
addWidget: addWidget
}
})
Scenario 1:
1. Click on "List" menu under the home page.
2. Click on "verify" button. notice the change in highlighted area with yellow. Text changes from "Chandan" to "singh1".
3. Click again on verify button. Text changes from "singh1" to "singh2". So i am able to communicate between two controller in this.
Scenario 2:
1. Repeat the scenario 1 till step 2.
2. Click on "PARAGRAPH" menu under home page.
3. Click on "List" menu under home page. Click verify button. The text wont change. It will remain "chandan".
Communication is not working as we change the state.
Also i have observed that the model is changing but same is not getting reflected in view. Moreover if we bind the view to rootscope, view is getting updated.
Please clarify.
When you switch between list and paragraph states, your list controller is destroyed (and recreated next time you go to list). So when it is recreated it gets a new scope.
The callbackFunction that is registered in your service, refers to the changeMyName() function on the old controller scope, so whenever you call addWidget() in your service, you're actually calling the callback in your old scope.
To make this work as expected (at least in your sample code here), you would have to change your service to allow changing the old callback in the addCallback()-function. Something like this:
var addCallback=function(callback){
callbackFunctions[0] = callback;
}
Related
I'm using angular-seed template (AngularJS) and I have routeProvider setup and such, now I want to execute a function (which resides in a factory), but only the very first time when the page gets loaded. I found many solutions for this, but I don't want to execute the code each time the users switches between tabs (via routeProvider of course, page doesn't get reloaded) - the code must be executed only when the whole page gets (re)loaded.
How should I approach this? I tried to call the function from run and then broadcast the event when page gets loaded, but there are no event listeners - I guess that is because the run part gets executed before the controllers are setup, so there are no listeners attached at the time when the event gets broadcast.
So, any suggestions how to approach this?
UPDATE
Use case:
when user types the url in the page, the page gets loaded
when pages gets loaded, a $http.get request is performed, which gets a random content
this content can be changed only by clicking a button, to explicitly request a change of content.
if users clicks to a different page e.g. view2 (routeProvider) and then back to the view1, the content must not change
when users refreshes the page (F5), the content changes again (or as already stated, by a click of a button)
Use the run method:
app.run(function(yourService){
yourService.cacheRandomContent();
});
It runs only once after the app is bootstrapped and services are created.
To access the data in controller, just inject the same service:
app.controller('someCtrl',function($scope, yourService){
yourService.getCachedRandomContent().then(function(resp){
$scope.data = resp.data;
});
});
Your service would be something like:
app.service('yourService',function($http){
var promise;
return {
cacheRandomContent: function(){
promise = $http.get();
},
getCachedRandomContent : function(){
return promise;
}
}
});
So I am relatively new to AngularJs and I am trying to figure out the best way for a tabController to remember what tab was previously clicked when switching to a new controller. So the situation would be I have 3 tabs. I click on tab 3 and then I click on something inside of it bringing me to a new controller and HTML template... What is the best way if I hit a "back" Button I created in that controller to remember exactly the state of it being the 3 tab.
I tried using $rootScope and then in each controller setting the tab number and setting the tabcontroller = $rootScope... but that was chaotic and too repetitive, and its not the right way.
This is not about $windoe.back(), this refers to coming up with a way that no matter where the navigation is the tab number is retained.
You can use a factory for this. In angular, a factory is a singleton, meaning only one instance of it exists for the whole project. Thus, by making something with it in one controller (and saving what you've did), you can access your changes in another controller.
angular.module('awesomeApp')
.factory('tabHistoryFactory', function () {
var tabHistory = {
setPrevTab: function(tab) { tabHistory.prevTab = tab; },
getPrevTab: function() { return tabHistory.prevTab; }
};
return tabHistory;
});
Then, in your first controller you'll have to inject this factory and before changing to another tab, just save the tab you're on using tabHistoryFactory.setPrevTab(tab). Then, in your second controller, you can access your previous tab by using tabHistoryFactory.getPrevTab(). Similarly, you can customize the behavior of your tab history by implementing other functions alongside those two.
Good luck!
I'm fairly new to angular, so bear with me. :-)
I have a list of contacts in one view. I put together a service with some setter and getter functions to hold the contact ID. When the user clicks a contact on the list view, it sets the ID in the service and moves to the edit form view. This is working well, but when I'm done editing and click to go back to the list view I want to clear the variables in the service. How would I do that?
I found one other answer on this topic, but I think it's using the built in angular router instead of ui-router.
Angular updating and clearing factory variables
Also, wouldn't the method in that answer also clear the variables when the user moved from the list to the edit form in the first place?
Thanks!
If it's a route change you can use $locationChangeStart, see $location
For example in your edit controller, register for the event on route change:
var onloc = $scope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
myService.cleanUp(whatever);
onloc();
});
I am using AngularJS 1.3. Assume I have created several routes in my application. But when user hits a specifc route/url & then tries to move to another route/url, I want to fire some event. I do not want to fire this event on every URL change.
So only when user comes out of this url http://localhost:9000/data/55677c/edit, I want to fire one function available in XYZ controller.
Here is my scenario:
I have a page which looks like this:
<div class="well">
<button id='edit-btn' type="button" ng-click='saveContent()'>
<div ng-include="'components/grid/comOne.html'"></div>
</div>
components/grid/comOne.html page contains one grid and it has its own controller which takes care of data management of the grid.
This grid is shown in two pages. One in editable mode and one is non-ediatble mode. While user is in editable mode and try to move out of the page without saving the info, I need to fire an event in order to discard ant changes user has made to the grid data.
Please suggest
If the listening controller is a parent controller you could $emit the event.
Or you could have a common service like this:
angular.module('x').factory('CommonLogic', function(){
var pageChangeListeners = [];
return {
listenToPageChange: listenToPageChange
};
function listenToPageChange(callback){
pageChangeListeners.push(callback);
}
function pageChanged(){
for(var i = 0; i < pageChangeListeners.length; i++){
pageChangeListeners[i]();
}
}
});
then when leaving that url (track that via $routeChangeStart) you can call: commonLogic.pageChanged()
In the controller where you want to take action just:
commonLogic.listenToPageChange(function(){..}).
Obviously this should be improved to avoid duplicate registration of the listener ... etc.
I hope I'm not overcomplicating this. Could you describe your use case in more detail ?
I guess you want to use $routeChangeStart:
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
});
You can put this in the scope of your current controller which might be edit as your url says.
From the docs:
$routeChangeStart
Broadcasted before a route change. At this point the route services starts resolving all of the dependencies needed for the route change to occur. Typically this involves fetching the view template as well as any dependencies defined in resolve route property. Once all of the dependencies are resolved $routeChangeSuccess is fired.
The route change (and the $location change that triggered it) can be prevented by calling preventDefault method of the event. See $rootScope.Scope for more details about event object.
Type:broadcast
Target:root scope
I am trying to create a menu structure, where the nav bar contains some information that is selected in one of the menu options.
See the plunkr.
What I try to do
Initially the welcome state is loaded. In this state a check is being done to see if the user was previously on the site and already selected a city which was either stored in the cookie or local storage. I have removed that part of the code since it doesnt add anything. Now it just checks to see if a value is already set or not (which initially it never is). Then it redirects to the selection of the city. After the user clicked a city, the nav bar should be updated from "Soon in:" to "Soon in <your selected city> The content does show the selected city, however the navbar does not. Also when debugging, the controller that belongs to the nav bar controller is not called again, so probably that's where my error is, I have not set up the nesting of the views correctly, yet I can not see what I missed. Can someone shine some light on this for me please?
Regards
Ronald
The soon in section is not updated because the way you are retrieving the selected city from the service is wrong, at the point of assignin the city to your $scope, nothing is selected, change your start.nav bar controller to:
controller: ["$scope", "CityService", function ($scope, CityService) {
$scope.$watch(CityService.getCity,function(v){
$scope.data = {city : v}
},true);
and it will work, see fork.
EDIT:
Which controller do you expect to see executed again? start.nav? That one isn't called again because you are never really moving out of it, all the states you go to after your app runs are children of start.nav. The way you retrieve the selected city is wrong because that line of code only runs once, and at that point nothing is assigned to city in your service.