How to watch controller asynchronous data in angular directive - angularjs

I define a directive in angular 1.4,which receives a scope parameter “b”:
(function() {
'use strict';
angular
.module('m')
.directive('mydirective', mydirective);
/** #ngInject */
function mydirective() {
var directive = {
restrict: 'E',
templateUrl: 'app/components/mydirective/mydirective.html',
scope: {
b: '='
},
controller: MydirectiveController,
controllerAs: 'vm',
bindToController: true
};
return directive;
/** #ngInject */
function MydirectiveController($scope, $state) {
var vm = this;
//here How to watch the parameter b to refresh the directive html result?
}
in html page:
<mydirective b="ctrl.b"></myupl>
in the business controller, b is got from an angular resource
PayService.getBusinessNumber().then(function(results){
vm.b = {business_id: results.no};
});
in index.route.js which define the route and the business controller,
$stateProvider
.state('payShowInfo', {
url: '/payShowInfo',
templateUrl: 'app/pay_show_info.html',
controller: 'PayShowController',
controllerAs: 'ctrl'
});
my problem is , When the directive loaded, the parameter “b” is undefined,  How to watch controller asynchronous data in angular directive? and then use the new value of “b” to refresh the html page?

If you define the directive parameter as "=", you mean that you will have two way data binding. So if you change the value in the controller, you will have the change reflected in the view.
angular.module('nib', [])
.directive('mydirective', function ($timeout) {
return {
restrict: 'E',
scope: {
b: '='
},
link: function ($scope, element, attrs) {
},
template: '<div>Test: {{b}}</div>'
};
})
.controller('ctrl',function($scope){
$scope.click = function(){ // emulating asynchronous request
$scope.test = 'testing';
}
})
See in the plnkr below:
http://plnkr.co/3qs1NpU1aIhKzxyCMXjh?p=preview

Related

Change Directive variable inside a directive is not working

I am trying to change a controller variable inside a directive and this is my code:
the main controller is :
angular.module("app").controller('vehicleManagementController', ['$scope', 'toastr', '$filter' ,
function ($scope, toastr, $filter) {
.....
$scope.filteredDevices = //Some List
$scope.allDevices = [];
}
}]);
and the directive is :
angular.module('app').directive('advanceSearchDirective', ['deviceAdvancedSearchService', 'mapService', function (deviceAdvancedSearchService, mapService) {
return {
restrict: "E",
controller: 'myDirectiveController',
scope: { filteredDevices: '=filteredDevices' },
templateUrl: '/app/templates/advanceSearchDirective.html'
};
}]);
angular.module("app").controller(myDirectiveController( $scope) {
$scope.search = function() {
$scope.filteredDevices = [];
$scope.$apply();
}
});
the thing is it faild to run the apply() method through this error.
and here how i am using it :
<advance-search-directive filtered-devices="filteredDevices" model="$parent"></advance-search-directive>
I have access to $scope.filteredDevices inside the directive controller but when i change its value it doesn't change in the main controller. what am I doing wrong?
if you want to save the changes on the parent controller scope you should use
scope:false,
change the directive to :
return {
restrict: "E",
controller: 'myDirectiveController',
scope: false,
templateUrl: '/app/templates/advanceSearchDirective.html'
};
here is an useful article .

Angular - pass object from directive to parent scope on click

I'm using an angular directive to generate a reusable template and show some data in it. The directive also has an ng-click that should take an object and pass it to the parent controller. I'm kind of stuck, not really sure how to pass that data from the directive controller to the scope of the parent controller. I read here but the circumstances are a bit different.
The js code of the directive:
angular.module("app")
.directive('userData', function() {
return {
restrict: "E",
templateUrl: "directives/userData/userData.html",
scope: {
userObj: "="
},
controller: function($scope){
},
link: function(scope, elements, attrs, controller){
}
}
});
And this is the directive html:
<div class="style" ng-click="displayFullDetails(userObj)">{{userObj.first_name}}</div>
Parent controller:
angular.module("app").controller("parentCtrl", ['$scope', function ($scope) {
angular.element(document).ready(function () {
getDataService.getJsonData().then(function (data) {
$scope.users = data.data;
})
});
}]);

Access parent property from directive controller with ControllerAs syntax and no $scope injection

This is a followed up question from this.
How can I access a property defined in MyController from MyDirectiveController to change its value or just read it and use it for something else? (commented line in the code).
angular
.module("app",[])
.controller('MyController', MyController)
.controller('MyDirectiveController', MyController)
.directive('myDirective', myDirective);
function MyController() {
var vm = this;
vm.foo = 'fooController';
}
function myDirective() {
return {
restrict: 'E',
scope: true,
controller: MyDirectiveController,
controllerAs: 'vm',
template: '{{vmMy.foo}} - {{vm.foo}}'
}
}
function MyDirectiveController() {
var vm = this;
vm.foo = 'fooDirective';
// vmMyfoo = 'fooDirective';
}
Here is the jsfiddle.
You can use bindToController (available from v1.3.x) setting of directive to bind values to controller instance instead of scope object.
function myDirective() {
return {
restrict: 'E',
scope: {
value: '='
},
controller: MyDirectiveController,
controllerAs: 'vm',
bindToController: true,
template: '{{vm.value}} - {{vm.foo}}'
}
}
and in HTML you pass value to directive like this:
<div ng-controller="MyController as vmMy">
<my-directive value="vmMy.foo"></my-directive>
</div>

Injecting resolve into directive with dynamic controller

I have a directive with dynamic controller which is passed via controller-name property.
Directive:
angular
.module('directives.panel', [])
.directive('panel', panel);
panel.$inject = ['$timeout', '$parse'];
function panel($timeout, $parse) {
var directive = {
restrict: 'EA',
transclude: true,
replace: true,
template: '<div class="panel panel-solid panel-table" ng-transclude></div>',
controller: '#',
name: 'controllerName',
controllerAs: 'panel',
link: linkFunc
};
return directive;
}
}
Is it possible to inject resolve 'taskbook' object into dynamic controller?
When I try to do that I get unknown provider. However injecting Resource service (GroupResource) works fine.
Is it possible to inject resolve in directive controller?
State
angular
.module('taskbooks.taskbook', [
'deployment.group',
'resource.deployment',
'resource.taskbook'
])
.config(TaskbookConfig)
.controller('TaskbookController', TaskbookController);
TaskbookConfig.$inject = ['$stateProvider', '$provide'];
function TaskbookConfig($stateProvider) {
$stateProvider
.state('taskbooks.taskbook', {
url: 'taskbooks/:taskbookId',
parent: 'taskbooks',
views: {
"mainContent#taskbooks": {
controller: 'TaskbookController as taskbook',
templateUrl: 'taskbook/taskbook.tpl.html'
}
},
resolve: {
taskbook: TaskbookPrepare
}
});
}
TaskbookPrepare.$inject = ['$stateParams', 'TaskbookResource'];
function TaskbookPrepare($stateParams, TaskbookResource) {
return TaskbookResource.get({
taskbookId: $stateParams.taskbookId
}).$promise;
}
Directive Controller
angular
.module('deployment.groups', ['resource.group'])
.controller('DeploymentGroupController',DeploymentGroupController);
DeploymentGroupController.$inject = ['$scope', '$element', '$attrs', 'GroupResource', 'taskbook'];
function DeploymentGroupController($scope, $element, $attrs, GroupResource, taskbook) {
}
Sort of... If this directive requires the resolve that is associated with this state, then it's safe to assume it will only ever be used in this state, correct?
Going on that idea, the directive can reference the controller set in the state and you can add the resolve to the controller scope.
Here's a very simplified version of what I'm saying...
angular
.module('taskbooks.taskbook')
.config([ $stateProvider, function ($stateProvider) {
$stateProvider
.state('taskbook', {
url: '/:id',
parent: 'taskbooks',
resolve: {
taskbook: [ '$stateParams', 'TaskbookResource', function ($stateParams, TaskbookResource) {
return TaskbookResource.get({
taskbookId: $stateParams.taskbookId
}).$promise;
}]
},
controller: ['taskbook', function (taskbook) {
this.taskbook = taskbook;
}],
controllerAs: 'taskController'
});
}])
.directive('someDirective', function() {
return {
restrict: 'EAC',
controller: 'taskController',
link: function (scope, el, attr, ctrl) {
var taskbook = ctrl.taskbook;
}
}
});
Do note, I removed a lot of the non-relevant code from yours just to get the point across quicker. Obviously this can be reworked into the structure you've written.

Accessing scope from parent directive angularjs

I have two directives and I wanted it to use it like so:
<m-list m-searchable></m-list>
So the two directives were m-list and m-searchable, now I want to access and manipulate the scope of the m-list when I attach the m-searchable directive.
I have this:
'use strict';
angular.module('app')
.directive('mList', function () {
return {
restrict: 'E',
scope: {},
controller: function($rootScope) {
var vm = this;
vm.name = 'joey';
},
controllerAs: 'ctrl',
bindToController: true,
templateUrl: '...'
};
});
And my m-searchable looks like this:
angular.module('app')
.directive('mSearchable', function () {
return {
restrict: 'A',
scope: {},
controllerAs: 'ctrl',
bindToController: true,
replace: true,
controller: function($rootScope, $scope) {
// I want console.log the scope of the directive where I attached the `m-searchable`
}
};
});
I want to console.log the scope of the directive where I attached the m-searchable. How do I access vm.name?
Firstly i think you will encounter $compile error due to both directive try to have their own isolated scope on the same element.
https://docs.angularjs.org/error/$compile/multidir?p0=mList&p1=mSearchable&p2=new%2Fisolated%20scope&p3=%3Cm-list%20m-searchable%3D%22%22%3E
Updated : better approach as suggested at http://juristr.com/blog/2015/01/learning-ng-directives-access-scope-controller/
is to pass the object between controller & directive
<m-list m-searchable name="name"></m-list>
app.directive('mList', function () {
return {
restrict: 'E',
scope: { name: "="},
controller: function($rootScope, $scope) {
var vm = this ;
vm.name = 'joey';
},
controllerAs: 'ctrl',
bindToController: true
};
});
http://plnkr.co/edit/OKVicRzjuH6L0xedF2qB?p=preview

Resources