(function(app) {
app.config(function($stateProvider, $httpProvider, $urlRouterProvider) {
//region Registering States
$urlRouterProvider.otherwise('/home');
var dashboard = {
name: 'home',
url: '/home',
templateUrl: 'home.html',
controller: 'homeCtrl'
};
var home = {
name: 'profile',
url: '/profile',
templateUrl: 'profile.html',
controller: 'profileCtrl'
};
$stateProvider.state(dashboard);
$stateProvider.state(home);
//endregion
});
app.controller('homeCtrl', ['$rootScope','$scope', function($rootScope,$scope) {
$rootScope.pageTitle = "home";
$scope.callEvent = function(){
$rootScope.$broadcast('newEvent',"data");
}
}]);
console.log('called');
}(angular.module('app', ['ui.router'])));
2'nd controller:
(function(app) {
app.controller('profileCtrl', ['$rootScope','$scope', function($rootScope,$scope) {
$rootScope.pageTitle = "profile";
$rootScope.$on('newEvent',function(ev,data){
alert('Event fired from home');
});
$scope.$on('newEvent',function(ev,data){
alert('Event fired from home');
});
}]);
}(angular.module('app')));
App with 2 controller:
1 controller: fired a event using $broadcast
2 controller: capturing event fired from 1'st controller.
But unable to accomplish that.
NOTE: If html page load once( 2'nd controller), $on event is fired else it's doesn't listen to any event.
For better understanding i had created a plunkr
Please first review the code
#vojta
Thanks
The problem is you are loading the controllers via states. This means they only initialize once the state becomes active (i.e you navigate to the html).
If you add a console log to profileCtrl you see that it does not get fired until the page is active.
Angular doesn't load the controller if it wasn't called.
Think of it as a singleton object which won't init until you will try to run it.
In your case, you set a controller for a specific route which means it will run only after you go to its route address.
What you actually will want to do is to have some directive Angular Directive
That will control on your menu bar that you will load on the main page and maybe every other page.
And for the home page, you should have a different controller that will be active only when the user is on the page.
As a side note, don't assume the "home" controller will be available once you leave the home page (Angular destroy).
Related
For some reason, the second Controller isn't receiving the data from the Service.
I'm trying to make the communication between two Controllers using one Service for it.
The View:
<div class="btn-wrapper" ng-controller="FirstController">
<a ng-href="" ng-click="doPath()" id="go" class="button">GO!</a>
</div>
The FirstController.js:
angular.module('app')
.controller('FirstController', function($scope, sharedService) {
$scope.doPath = sharedService.searchPath;
});
The sharedService:
angular.module('myServices', [])
.service('sharedService', function($rootScope) {
this.searchPath = function() {
console.log("I got the service!");
$rootScope.$broadcast('Search', {
data: 'something'
});
}
});
And the SecondController.js
angular.module('app')
.controller('SecondController', function(sharedService, $scope) {
$scope.$on('Search', function(event, data){
console.log(data);
//this.search(); => I intent to run this function after this
});
});
The event is dispatched by a button in the View, that calls the doPath() function. This function does communication with the Service sharedService and the message "I got the service" is displayed.
However, the app stops here. And the communication between Service and the second Controller, using $rootScope.$broadcast, seems that not happening (the data isn't showing on console, neither any error).
I found some solutions here. I have tried already all of answers, so the problem is not the same, cause still not working.
EDIT
The ngRoute is here (app.js):
angular.module('app', ['ngRoute', 'myServices'])
.config(function($routeProvider){
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'FirstController'
})
.otherwise({
redirectTo: '/'
});
});
As everyone suggested 'Instantiation' of the Second controller is needed.
<div ng-controller="firstController">
//code
</div>
<div ng-controller="secondController">
//code
</div>
Like above.
I know you have used 'ngRoute'. Until you change your view the second controller will not be loaded in 'ngRoute' whereas in above code both the controllers are in the same view. That is why above code works and 'ngRoute' does not.
SecondController is not instantiated by Angular because you are referring only FirstController from html. You need to instantiate the SecondController on the same html using parent child or sibling relationship depending on your application.
Of course, I should mention that I'm new to this thing, so sorry if this is something trivial.
So I pretty much have 2 routes (views). localhost:3000 takes in and loads up a list of objects and localhost:3000/:slug shows information of the product the users wants to see more info about.
The initial listing is fine. You visit localhost:3000 and you see a list of items.
listPhoneController.js:
angular.module('cmscApp').controller('listPhoneController', ['$scope', '$http', '$location', 'searchBoxFactory',
function($scope, $http, $location, searchBoxFactory) {
$scope.listInfo = searchBoxFactory;
$scope.phoneList = [];
$http.get('/api/getallphones').then(function(res) {
$scope.phoneList = res.data;
}, function() {
$scope.errorMsg = 'Error in reaching data';
});
}]);
list.html:
<!-- ... --->
<div class="result" ng-repeat="phone in phoneList | hasImageFilter:listInfo.imageRequired
| nameFilter:listInfo.phoneName
| priceFilter:listInfo.price.from:listInfo.price.to">
<!-- filters don't seam to be the problem (removing them still causes the issue) -->
<a ng-href="/phone.slug">More info...</a>
<!-- ... -->
</div>
Now, if I click on the a tag, I get redirected to that phone's information view (ie. localhost:3000/samsung-galaxy-s4) and information is being loaded correctly. I also have a back button there, with a simple <a ng-href='/'>Back</a>
But, when I go back, even though the URL changes back to localhost:3000, the list doesn't appear. I get no errors, nothing, but the div's aren't there (when inspecting, nor anything).
Is this because $http is async, so it tries to load the page before it gets the info? If that's the case, why doesn't it just bind the data, as usual?
Here's my config:
angular.module('cmscApp').config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: '/pages/list.html',
controller: 'listPhoneController',
controllerAs: 'lpc'
})
.when('/:phoneSlug', {
templateUrl: '/pages/detail.html',
controller: 'detailPhoneController',
controllerAs: 'dpc'
})
.otherwise({
templateUrl: '/error/404.html'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
Any sort of help is more than welcome!! I thought about storing the data from $http to a factory, so then it loads that data every time the controller is run, while updating it as well. would that be a viable solution, or is there something better?
Turns out the scope didn't bind for some reason, so I had to edit the $http.get().then() method:
$http.get(...).then(function(res) {
$scope.data = res;
$scope.$apply();
}, function() { ... });
for anyone encountering a similar issue
I'm using ui-router to display 2 ui-views, one within the other. They are organized like this:
.state('itemAbstract', {
url: '/items',
abstract: true,
templateUrl: 'client/views/item.ng.html',
controller: 'moveCtrl',
})
.state('item', {
url: "/:itemId",
parent: "itemsAbstract",
views: {
"otherpage":{
templateUrl: 'client/views/other-page.ng.html',
controller: 'otherPageCtrl'
}
}
})
I run the folloowwing in the otherpage controller when an item is clicked.
$rootScope.$broadcast("somethingClicked",obj)
I try to listen for the event in the item controller:
$scope.$on("somethingClicked",function(a,b){
console.log(a)
console.log(b);
})
Unfortunately, this function never gets called. I tried putting this listener function in the otherpage controller, and it was called correctly when the event happened. For some reason, though, this broadcast isn't getting transferred across scopes. That was the whole reason I was using this, to trigger an action in the parent when something in the parent is clicked. Any ideas on why this is not working?
Here is my controller for the item
angular.module('mm').controller('itemCtrl',
function($scope, $meteor, $rootScope, $state, $stateParams) {
var s = $scope;
s.rs = $rootScope;
$scope.$on("somethingClicked",function(a,b){
console.log("there as a click")
console.log(a)
console.log(b);
})
}
I used Batarang to debug and found that despite this code, $scope is not even registering an event listener. $scope.$$listeners does not have a listener for the somethingClicked event. Very strange, and it doesn't make sense why this isn't working.
Maybe you have independent controllers with no inheritance applied. Inheritance on $scope is declared simply by nesting the controllers on your view. In that case you may use $rootscope to broadcast or listen to event as:
//ctrl1
$rootScope.$broadcast("somethingClicked",obj);
//ctrl2
$rootScope.$on("somethingClicked",function(a,b){
console.log(a)
console.log(b);
});
Take a look at this simple demo as well as an older question on Stack Overflow.
EDITED
Based on your sample code I had no problem at all communicating using $rootscope.
The state declaration use an abstract parent controller and a fetched child controller mapped into the view as:
$stateProvider
.state('test', {
url: '/test',
controller: 'pctrl',
views: {
'main': {
template: '<div ng-controller="pctrl">{{test}}</div>' +
'<div ui-view="childview"></div>'
}
}
})
.state('test.child', {
url: '/test/child',
controller: 'cctrl',
views: {
'childview': {
template: '<div ng-controller="cctrl" />'
}
}
});
Here is a full working demo
Answer found - I had misconfigured my routes file, and had the wrong controller specified for the page I was loading. That's why none of my event listeners registered!
I have different views each created by a different controller. At a particular time only one of the views is visible.
I want to switch from one view to another view through a function of the controller of the first view and after that I want to call a method of the second view controller.
My problem is how should I call this method in an angular way?
I know the possiblity using $broadcast and $on but that smells a little bit.
The other choice ist to find the scope in the dom and calling the method via scope. But that is even more ugly.
What is the best solution?
You can use services to communicate between controllers. While you could create a generic shared service to have a central point to subscribe to and broadcast events, services are easier to maintain over time.
You can use Angular Routing
Check out the documentation. This is an excerpt from the documentation. You can make links like
Link
For the first route and so on.
phonecatApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
Okay it is done and simpler as expected.
The idea is to use a service used in both views (controllers), that contains a 'execution boolean'.
The first view set the boolean to true, the second set a watch on this boolean and therefore is called and can call the desired method.
In the service:
trigger: function(name) { model[name] = true; },
setTriggerWatch: function(scope, name, callback) {
scope.$watch(function value() {
return model[name];
}, function listener(newValue, oldValue) {
if (newValue) {
callback();
}
});
},
In the destination controller:
sessionData.setTriggerWatch($scope, 'createSession', function callCreateSession() {
_createSession();
});
In the source controller:
sessionData.trigger('createSession');
Is it possible to init a scope and ng-view in load?
Problem:
I have an AngularJS App with a list of Resellers. You can choose a reseller on a map and open details in a overlay-div (calling it with ng-show="show") on the route
when(
'/dealer/:id', {
templateUrl: 'files/tpl/dealer-details.html?19',
controller: 'DealerDetailsCtrl',
activetab: 'details'}
).
The client wants now that when a customer opens the page, an initial details-overlay is open with the details.
Solution (possible):
Is it possible to, maybe ng-init, send the hardcoded :id of the chosen reseller to the controller and trigger the detail-overlay, so that it opens on load? Or maybe to trigger the route with the ID.
If I understand you correctly, you want a default value for :id if not provided?
Best option is to have two when clauses in your $routeProvider:
$routeProvider.when(
'/dealer', {
templateUrl: 'files/tpl/dealer-details.html?19',
controller: 'DealerDetailsCtrl',
activetab: 'details'}
);
$routeProvider.when(
'/dealer/:id', {
templateUrl: 'files/tpl/dealer-details.html?19',
controller: 'DealerDetailsCtrl',
activetab: 'details'}
);
In your controller you can then assign a default value if not defined:
$scope.dealer = $routeParams.id || 'defaultDealerId';