controller function not called from ng-click - angularjs

I have a controller that ive added a function to but cant get the function to be called from ng-click on an anchor. Ive looked at similar posts but cant really see what I could be missing. Its as though the controller function cant be seen?
The module and controller:
var commonModule = angular.module('common', ['ngRoute', 'ng.ckeditor']);
var mainModule = angular.module('main', ['common']);
//mainModule.config(function ($routeProvider, $locationProvider) {
// $locationProvider.html5Mode(true);
//});
commonModule.factory('viewModelHelper', function ($http, $q, $window, $location) {
return MyApp.viewModelHelper($http, $q, $window, $location);
});
commonModule.factory('validator', function () {
return valJs.validator();
});
mainModule.controller("rootViewModel",
function ($scope, $http, $q, $routeParams, $window, $location, viewModelHelper, $rootElement) {
//test
console.log("creating controller");
var self = this;
viewModelHelper.apiGet('api/PageContent/1', null,
function (result) {
$scope.htmlEditor = result.data;
});
$scope.ToggleEditor2 = function () {
//test
console.log("hello");
if ($scope.editorVisible == true) {
$scope.editorVisible = false;
}
else {
$scope.editorVisible = true;
}
}
});
The controller is referenced at the root level of the page:
Which in this case since im using ASP.Net MVC, is in my _layout.cshtml
<body data-ng-app="main" data-ng-controller="rootViewModel">
In a (mvc) view that gets loaded, I have a button with ng-click that calls the ToggleEditor2 function, but its never called. Cant get a breakpoint to hit in the chrome dev console and I dont see anything written to the log either.
<input type="button" ng-click="ToggleEditor2()" value="test me" />
Update:
If I wrap that anchor with a div and specify the "rootviewModel" controller there, the log message gets written. Hmmm - something tells me its related to scope?
<div data-ng-controller="rootViewModel">
<input type="button" ng-click="ToggleEditor2()" value="test me" />
</div>

Problem
A common problem with $scope is that when using any sort of nested controllers or modules, your $scope's can step on each other and cause issues like you have experienced.
Solution
Using Angular's "Controller As" syntax is the recommended solution for this problem. It allows you to create multiple instances of the same controller, while defining and maintaining a unique scope for each instance.
This Article is a great resource I used to understand and implement this new syntax.

Related

Ui bootstrap doesn't show after adding object to controller

So my ui bootstrap model window is working correctly but when I add an object to the controller it stops showing and it doesn't give me any error in consol.
When my controller looks like this:
"use strict";
app.controller('RegisterModalCtrl', ['$scope', '$location', '$uibModalInstance', '$http', 'ngAuthSettings', 'registerService',
function($scope, $location, $uibModalInstance, $http, ngAuthSettings, registerService) {
var $ctrl = this;
$ctrl.cancel = function() {
$uibModalInstance.dismiss('cancel');
};
/*
$ctrl.registerInfo = {
email: $ctrl.registerData.email,
nick: $ctrl.registerData.nick,
password: $ctrl.registerData.password,
password_confirmation: $ctrl.registerData.confirm_password
};
*/
$ctrl.registerSubmit = function(registerInfo) {
console.log('im in registerSubmit controller function');
registerService.registerUser(registerInfo);
$uibModalInstance.dismiss('cancel');
};
$ctrl.showCookiesRules = function() {
$location.url("/cookiesrules");
$uibModalInstance.dismiss('cancel');
};
$ctrl.showRules = function() {
$location.url("/rules");
$uibModalInstance.dismiss('cancel');
};
}]);
Everything works just fine but when i delete /* just before registerInfo object it stops showing. What is wrong with this object? I want it to create this object to pass it in function and then pass it to function in service.
So what you should do is initiate $ctrl.registerInfo:
$ctrl.registerInfo = {};
The data doesn't exist when the controller runs, so you are trying to set the properties of $ctrl.registerInfo without non-existent data. Once your form is filled out, the properties/data will be set.
An alternative option would not be to initialize at all, and simply set your form model to registerData.confirm_password, and when you call registerSubmit, call it with registerSubmit(registerData). That will send the data to that method without having to initialize in the controller:
<input type="text" placeholder="powtórz hasło"
ng-model="registerData.confirm_password" />
<!-- abbreviated (other form fields here -->
<input type="submit" ng-click="registerSubmit(registerData)" />
If you need the data afterwards, in registerSubmit, add a line:
$ctrl.registerInfo = registerInfo;
However, I am not sure you'd want to hang onto the password there.
AngularJS Form Docs: https://docs.angularjs.org/guide/forms

ng-show not working on state change for factory function

I want to change text from login to logout once user is successfully logged in thereby changing url from home to dashboard.
$stateProvider.state('home',{url:'/',views:{'':{templateUrl:'./partials/home/home.tpl.html'},'navbar#home' {templateUrl:'./partials/navbar/navbar.tpl.html'},'lsidebar#home':{templateUrl:'./partials/sidebars/lsidebar.tpl.html'},'content#home'{templateUrl:'./partials/content/content.tpl.html'}},authenticate:false })
.state('dashboard',{url:'/dashboard',views:{'':{templateUrl:'./partials/home/home.tpl.html'},'navbar#dashboard':{templateUrl:'./partials/navbar/navbar.tpl.html'},lsidebar#dashboard': {templateUrl:'./partials/sidebars/lsidebar.tpl.html'},'content#dashboard':{templateUrl:'./partials/dashboard/dashboard.tpl.html'}},authenticate:true})
sample Factory :
coreApp.factory('AuthFactory',function($http){
var obj={};
var isAuthenticated=false;
obj.login=function(data){
return $http.post('http://reqres.in/api/login',data);
}
obj.userInfo=function(){
isAuthenticated=true;
return {name:'xyz',balance:'10.00'};
}
obj.isAuthenticated=function(){
return isAuthenticated;
}
return obj; });
HTML :
<a ui-sref='login' ng-show='!AuthFactory.isAuthenticated()'><i class="glyphicon glyphicon-off"></i> Sign in</a>
<a ui-sref='logout' ng-show='AuthFactory.isAuthenticated()'><i class="glyphicon glyphicon-off"></i>Logout </a>
boostrap :
.run(['$rootScope', '$state','$stateParams','AUTH_EVENTS','AuthFactory',function($rootScope, $state, $stateParams,AUTH_EVENTS,AuthFactory){
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if(toState.authenticate && !AuthFactory.isAuthenticated())
{
$state.transitionTo("login");
event.preventDefault();
}
console.log("AuthFactory"+AuthFactory.isAuthenticated());
});
$rootScope.$on(AUTH_EVENTS.notAuthenticated,function(event){
console.log('You not logged in');
});}]);
Issue is when user gets logged in root scope is updated and prints value of AuthFactory.isAuthenticated() as true and also url is being changed but my text in lsidebar.tpl.html is not changed.
I did a bit googling I found out that $scope.$apply is a way to do it.But I am confused what is the right way for such case or is it ok to use $scope.$apply on factory function.
You can't use services in your templates directly. Services are just objects that Angular knows how to inject in dependable functions.
That said, you need to inject the service and define property in the scope of the controller with a link to the service to be able to use it in your templates.
JS
app.controller('myController', ['$scope', 'myService', function ($scope, myService) {
$scope.myService = myService;
});
HTML
<div ng-controller="myController">{{ myService.someGetterFn() }}</div>
Or
JS
app.controller('myController', ['myService', function (myService) {
this.myService = myService;
});
HTML
<div ng-controller="myController as ctrl">{{ ctrl.myService.someGetterFn() }}</div>
AngularJS is a little bit confusing when dealing with in-line expressions. Try:
ng-show="(!AuthFactory.isAuthenticated())"
Also, and in relation to $apply(), the way to use it (not always applicable though) is:
$scope.$apply( aaa = true );
Be aware that this cannot be invoked in all situations (e.g. if invoked while Angular is digesting changes, you will get an error message).

Input type number is not being set on $scope init. How could I set the input on the controller init?

I have a controller that have defined a route parameters when I open the controller from a link with its parameters the init capture those params but it does not show the data on the form. The init function is ran on controller initialization and it captures all route parameters well but when I assign it to the model on the scope the input is not getting the value. I tried $digest and $apply but that does not work there. How can I make the number input show the value from the route only on initialization?
My route configuration :
when('/mypage/:ofid/:nfid?', {
templateUrl: 'admin/templates/mytemplate.html',
controller: 'MyTemplateController'
}).
My controller-fragment:
angular.module('MyModule')
.controller('MyTemplateController', ['$scope', '$log', '$routeParams', .....
function ($scope, $log, $routeParams, ...) {
$scope.oldId;
$scope.newId;
...
$scope.init = function () {
$scope.oldId = $routeParams.ofid;
newId = $routeParams.nfid;
}
$scope.init();
}
Template fragment:
<input type="number"
class="form-control"
ng-model="oldId"
required/>
$routeParams are passed as strings, and parsing is required for using these in numeric inputs.
Using $scope.oldId = parseInt($routeParams.ofid); works for this situation.
app.controller('MyTemplateController', ['$scope', '$log', '$routeParams',
function($scope, $log, $routeParams) {
$scope.oldId;
$scope.newId;
$scope.init = function() {
$scope.oldId = parseInt($routeParams.ofid);
$scope.newId = $routeParams.nfid;
$log.log($scope.oldId, $scope.newId);
};
$scope.init();
}
]);
The $log.log($scope.oldId, $scope.newId); at the end of the init shows 2, '1' in the Chrome console, which is definitely proof that the parseInt worked, and the textbox is filled correctly.
http://plnkr.co/edit/Oc777cYulT11KQMqdnmd?p=preview
try that:
ng-init="desiredValue = $scope.realValue"
According to angular's documentation
"The ngInit directive allows you to evaluate an expression in the current scope."
But should be used with caution
https://docs.angularjs.org/api/ng/directive/ngInit

How to Forward $scope from Controller to Controller AngularJS?

I am New to Angular Js.
Is It Possible to Forward Scope of the RestaurantController to MenuController Code as Follows
Example :-
angular.module('restaurants').controller('RestaurantController', ['$scope',
function($scope) {
$scope.restaurantid="435scvcxvbrcvbnvn";
}
]);
And i assigned restaurant id as New scope in Menu Controller as Follows
angular.module('menus').controller('MenuController', ['$scope',
function($scope) {
$scope.currentrestaurantid= $scope.restaurantid;
alert($scope.currentrestaurantid); // showing Null
}
]);
The Restaurant Id is not Persisted .. Honestly i feel that some thing is Missing .
How to Get the Id From Restaurant controller to Menu Controller ?
Try inheritance
angular.module('restaurants', []);
angular.module('menus', ['restaurants']);
angular.module('restaurants').controller('RestaurantController', function($scope) {
$scope.restaurantid="435scvcxvbrcvbnvn";
});
angular.module('menus').controller('MenuController', ['$scope','$controller',
function($scope, $controller) {
$controller('RestaurantController', {$scope: $scope});
$scope.currentrestaurantid= $scope.restaurantid;
}
]);
Working fiddle
I propose use the rootScope to do that.
Use the $broadcast to notify the other controller the change on the firsts controller scope.
$rootScope.$broadcast("restIDUpdated", {
restaurant: $scope.restaurantid
});
Use the $on to receive the notification in the second controller about the event that happend in the first controller.
$scope.$on("restIDUpdated", function (event, args) {
$scope.restaurant = args.restaurant;
});
There is an example of this here
Try something like this.
angular.module('restaurants').controller('RestaurantController', function($scope) {
$rootScope.$broadcast("restIDUpdated", {
restaurantid: 435scvcxvbrcvbnvn
});
});
angular.module('menus').controller('MenuController', ['$scope','$controller',
function($scope, $controller) {
$controller('RestaurantController', {$scope: $scope});
$scope.$on("restIDUpdated", function (event, args) {
$scope.currentrestaurantid= args.restaurantid;
});
}
]);
But to be honest I am not sure if this mechanism works with two different angular apps, I know using the same module it works but not sure what is going to happen using two different modules, but take a look at the API
A pattern I commonly use is to create an angular service and inject it into controllers I want to share data with. something like this...
angular.module('restaurants', []);
angular.module('menus', ['restaurants']);
angular.module('restaurants').service('RestaurantService', function() {
this.restaurantid = "435scvcxvbrcvbnvn";
});
angular.module('restaurants').controller('RestaurantController', function($scope, RestaurantService) {
$scope.restaurantid = RestaurantService.restaurantid;
});
angular.module('menus').controller('MenuController', function($scope, $controller, RestaurantService) {
$scope.currentrestaurantid = RestaurantService.restaurantid;
});
As said here, injectable service as generic way for your situation.
But I'd like to point more pretty way, using markup and controller as (docs) expression.
For example you have following controller:
.controller('RestaurantController', function($scope) {
$scope.restaurantid="435scvcxvbrcvbnvn";
})
and you can bind it to variable in the scope:
<div ng-controller="RestaurantController as restaurant">
<div ng-controller="MenuControllerOrAnyOther">
restaurant id = {{restaurant.restaurantid}}
</div>
</div>
Remarks
This approach would be nicer if you need restaurantid ONLY in markup, e.g.
<button ng-click="select(restaurant.restaurantid)">
This looks ugly, if you want to use restaurantid in js code (you should use injectable services then):
var restaurantid = $scope.$eval('restaurant.restaurantid');

Calling a scope function in different controller

I have a function defined in a controller , I want to call it in another controller.
I tried to attach it to the $rootscope so I can see in the other controller , but I couldn't .
Is there a way for calling it, without attaching it to the $rootscope?
As far as I know in AngularJS you can share info between controllers in 3 ways:
1 - Creating a Service.
2 - Creating a function linked to $rootScope.
3 - Using events ($broadcast and $on). I use a lot this method in my projects.
I think your problem is that you don't instantiate the controllers in
the proper order or one of them is never instantiated, therefore the
function you want to link to $rootScope in that controller or the broadcast event never fires.
E.G If you want to call a function linked to $rootScope in the 2 controller from the
first one, it is impossible because the 2 controller is instantiated after the first one.
This case happens when you make calls on application runtime.
I will implement your method with some changes:
HTML:
<div ng-controller="MyCtrl_1"></div>
<div ng-controller="MyCtrl_2">
<button ng-click="send()">Send Mess</button>
</div>
JS:
var myApp = angular.module('myApp',[]);
function MyCtrl_1($scope, $rootScope) {
$scope.$on('RenderPage', function (event, PageId) {
$scope.RenderPage = PageId;
alert($scope.RenderPage);
});
};
function MyCtrl_2($scope, $rootScope) {
$scope.MasterPageId = 10;
$scope.send = function(){
$rootScope.$broadcast('RenderPage', $scope.MasterPageId);
}
};
Use carefully $broadcast and $emit, because has different behavior each one.
Try here: http://jsfiddle.net/1ypkb4s9/
Otherwise, post your error.
Simply wrap them with a "father controller":
HTML:
<div ng-app="myApp" ng-controller="myOuterCtrl">
<div ng-controller="myInnerCtrl1">
<button ng-click="outerClick()">Outer Click</button>
</div>
<div ng-controller="myInnerCtrl2">
<button ng-click="innerTwoClick()">Inner Click</button>
</div>
</div>
JS:
angular.module('myApp', []).
controller('myOuterCtrl', function ($scope) {
$scope.outerClick = function () {
console.log('outer click');
}
}).
controller('myInnerCtrl1', function ($scope) {
// nothing here!!
}).
controller('myInnerCtrl2', function ($scope) {
$scope.innerTwoClick = function () {
console.log('inner two click');
}
});
JSFIDDLE.
if you want to use the same function in two or more controllers you might need a service.
or use events
function firstCtrl($scope)
{
$scope.$broadcast('someEvent', [1,2,3]);
}
function secondCtrl($scope)
{
$scope.$on('someEvent', function(event, mass) { console.log(mass); });
}

Resources