How to access a function defined in a ui-router state controller - angularjs

I have an angular ui-router state with a controller as follows.
$stateProvider.state('contacts', {
template: '<h1>{{title}}</h1>',
controller: function($scope){
$scope.title="MyTitle";
$scope.myFunction= function(){
//do something
};
},
data:{
list:[
{
item:"item1",
callback:{{myFunction}}
}
]
}
})
As shown in the code above, the state controller has a function attached to the scope called "myFunction".
I also have a directive which accesses this state. In that directive, I want to call the myFunction as callback when item1 is clicked(i have a button corresponding to item1 mentioned in data section).
Please let me know how i can call the myFunction method from my directive.

Related

Angularjs dialog call another controller function on close

AngularJs:
I'm trying to show an edit modal box. For this, I'm using $mdDialog of AngularJs material design. Here is my code:
angular.module('main').controller('UserCtrl', ['$scope', function($scope){
function loadUser(){
...
}
function showEditSale(index) {
var sale = $scope.user.Sales[index];
$mdDialog.show({
clickOutsideToClose: true,
fullscreen: $scope.customFullscreen,
parent: angular.element(document.body),
locals: {
sale: sale
},
templateUrl: 'front/templates/user/edit-sale.html',
controller: 'UserSaleCtrl'
})
.then(function(answer) {
}, function() {
});
}
}]);
angular.module('main').controller('UserSaleCtrl', ['$scope', function($scope, sale){
$scope.sale = sale;
function updateSale(){
...
**Need to reload user**
}
}]);
When I click on edit button against user sale, I call showEditSale passing the index of user.Sales item. A popup is displayed and I can edit values there. When clicking on update, an api is called which is updating sale information.
The problem is I want to reload this user. To reload, I have to call function from another controller.
My questions are:
Is there another way to pass data to dialog box instead of injecting in controller?
Do I have to use emit event of AngularJs to call function of another controller?
Can I somehow use same controller? I tried but I think $scope is being reset for modal dialog.
I added following code in UserSaleCtrl:
function updateSale(){
...
$rootScope.$broadcast('reloadUser');
}
Added following code in UserCtrl:
$scope.$on('reloadUser', function(event) {
loadUser();
});

unable to get $scope form name on load

I'm trying the retrieve the form name inside my angularjs component while the form is being loaded as I wanted to set the form state to dirty based on some data validations that were resolved in to the component. I'm able to access the form name once the form is completely loaded say inside a submit, however i'm unable to do that on the load how can I do that. I'm using ui.router hence the controller name is being set based on the state.
<form class="form-horizontal" name="detail.myForm">
<button ng-click="detail.submit">
</form>
app.component('myDetail', {
bindings: {
alldetails: '<'
},
templateUrl: '/app/detail.html',
controllerAs: 'detail',
controller: function ($state, $transitions, $scope) {
var detail=this;
/*validateData in the alldetails here */
$scope.detail.myForm.$setDirty(); // issue here saying undefined
detail.submit = () =>{
$scope.detail.myForm.$setPristine() //works without any issue
}
}
This happens since the DOM isn't ready on your controller's construction. You have to use the $onInit callback instead. From AngularJS docs:
$onInit() - Called on each controller after all the controllers on an element have been constructed and had their bindings initialized (and before the pre & post linking functions for the directives on this element). This is a good place to put initialization code for your controller.
Also, it'd be better to inject the ngFormController by using the require object instead of assigning it to your model.
Here's a fiddle with a working example. The relevant code is:
.component('myDetail', {
template: '<h1>Details Component</h1>',
controllerAs: 'detail',
// By requiring the form controller, angular will
// create a 'formCtrl' property on your controller with the
// ngFormController instance of the parent form.
require: {
formCtrl: '^form'
},
controller: function() {
// We can't just acces the formController here, couse it will be
// undefined, since the dom isn't ready yet. So we have to use the
// $onInit callback that will be executed by angularjs.
this.$onInit = function() {
/*validateData in the alldetails here */
this.formCtrl.$setDirty();
}
}
});

Why is binding value not available in controller immediately in angular

I'm trying to bind some values in an angular 1.6 component that should be available to the controller code.
I must be misunderstanding it, but the variables aren't available when the controller runs. The only way I've managed it is by putting a $timeout in to push the code into the next digest cycle.
What am I doing wrong here?
The relevant section is here:
var SelectorCtrl = ['$scope', '$http', '$timeout',
function ($scope, $http, $timeout) {
var self = this;
alert("1: " + self.hierarchyId);
// I'm not 100% sure why this has to be in the next digest cycle
$timeout(function(){
$scope.categories = self.categories;
alert("2: " + self.hierarchyId);
});
}
app.component('categorySelector', {
templateUrl: 'categorySelector.html',
controller: SelectorCtrl,
bindings: {
hierarchyId: "#",
disabled: "=",
categories: "=",
onSelectionChanged: "&"
}
});
See plunker: https://plnkr.co/edit/8rtDuCawdHaiXzQU5VBR
This is because of $compileProvider.preAssignBindingsEnabled(flag) introduced in Angular 1.6, you can configure it on config cycle on $compileProvider
If disabled (false), the compiler calls the constructor first before
assigning bindings.
The default value is true in Angular 1.5.x but will switch to false in
Angular 1.6.x.
You will get all bindings inside $onInit lifecycle event of Angular component, where all the bindings would be available(if binding passed synchronously).
self.$onInit = function() {
$scope.categories = self.categories;
alert("2: " + self.hierarchyId);
};
Note: It's bad practice to mix $scope with this. Rather avoid using $scope to make your code Angular 2 migration proof.
If you want binding to be available when controller function instantiate then you could set $compileProvider.preAssignBindingsEnabled(true). Which will make self.categories(bindings) value.
app.config(function($compileProvider){
$compileProvider.preAssignBindingsEnabled(true)
});
Similar answer
Angular 1.7.x update
As of Angular 1.7.x, the $compileProvider.preAssignBindingsEnabled(flag) is gone, and it is no longer possible to assign bindings before the constructor.
To work around this, you need to define a link function in your directive definition. You can make this function call a method on your controller like this:
app.directive("directive", function() {
return {
controller: DirectiveController, // bind controller any way you want
controllerAs: "ctrl",
bindToController: true,
link: function(scope) {
scope.ctrl.init(); // this will call an init() function on your controller
}
}
});

Calling of one controller from another

While loading I am calling one controller, however I am using ng-include to import another HTML page in the main HTML page.
I want to call ng-controller of included page.(How to call a child controller from a parent controller using ng-init)
You need not call it seperately. Just add 'ng-controller' directive on the 'ng-include' element and assign its controller as shown below:
<div ng-include="template.url" ng-controller="YourController"></div>
The best way to do this is to have the parent Controller broadcast an event that the child scope will register:
.controller("ControllerParent", [$scope, function($scope) {
$scope.alertChild = function() {
$scope.$broadcast("custom-event", data);
};
});
.controller("ControllerChild", [$scope, function($scope) {
$scope.$on("custom-event", function(event, data) {
//do something with event
};
});

AngularJS - Updating a variable in custom directive

I have declared a variable in parent scope in one of my controllers.
$scope.myValue = true;
This value is fetched in the custom directive easily. But when the value is updated in the parent controller it is not reflected in the custom directive.
My question is how can we let the directive know that the "myValue" is changed?
If the info is not suffice kindly let me know.
In your parent controller, upon changing the value of the variable, you can broadcast an event like this -
$scope.$broadcast('valueChanged', {
val: $scope.myValue // pass in any object you want
});
And then in your child controllers, handle it like -
$scope.$on('valueChanged', function (event, data) {
console.log(data); // get the same object here
});
$broadcast fires the event down, so this should work in your case.
You can watch the value inside the directive, like this:
app.directive('directive', function() {
return {
scope: true,
link: function($scope){
$scope.$watch('$parent.myValue', function(newVal){
console.log(newVal);
});
}
};
});
Link demo: https://jsfiddle.net/mzrja04L/

Resources