I'm trying to create a dynamic directive that will receive his binding options from attributes.
This is my controller view:
<div ng-controller="OtCtrl">
<div ng-include src="'/client/views/openTradeView.html'"></div>
</div>
my View:
<div>
{{name}}
<div swings binding="Risk" title="Risk"></div>
<div swings binding="Amount" title="Amount"></div>
</div>
This is my directive View:
<div>
{{title}}
-
{{amount}}
+
</div>
This is my directive:
app.directive("swings", function () {
return {
replace: true,
scope: {
title : '#title',
amount: '=binding',
extra: '=bindingExtra'
},
resctrict: "A",
controller: function($scope){
$scope.minus = function (event, binding) {
$scope.amount -= 1;
console.log(binding)
}
$scope.plus = function (event) {
$scope.amount += 1;
}
},
templateUrl: '/client/views/swingsDirectiveView.html'
}
});
And finally my Controller:
app.controller("OtCtrl", ['$scope', function ($scope) {
$scope.Amount = 400;
$scope.Risk = 100;
setInterval(function(){
console.log($scope.Risk)
},2000);
}]);
I know that when I use ng-view, angularjs creates new scope. My issue that when I click plus or minus, the amount in the directive updates but the Risk model in the controller not, but on first load directive takes the risk init value and set the amount.
How can I fix this issue.
Thanks
I would suggest creating a model property in your controller like so:
app.controller("OtCtrl", ['$scope', function($scope) {
$scope.model = {
Amount: 400,
Risk: 100
}
}]);
Then, bind it to your directive via:
<div swings binding="model.Risk" title="model.Risk"></div>
What is likely happening is that scope inheritance is creating a copy of Amount and Risk (since they're primitives); whereas creating an object like this causes the reference to get copied, meaning the scope hierarchy shares the same data.
Related
I have a directive as follows
<div ng-controller=prdController as prd>
<my-dir data=prd.data ng-click=stateChanged()></my-dir>
</div>
where prd.data is an object. In my directive I did the following
app.directive('myDir',function(){
return {
scope:{
data:'=data'
},
templateUrl: './templates/testtemplate.html',
controllerAs:'bd',
controller:function($scope,$attrs){
this.stateChanged = function (value) {
$attrs.data = { 'fd','sdfs'};
}
}
});
I am unable to modify the data value within the controller how do I proceed thanks in advance.
I think the problem could be in the way you trying to get data object in your controller.
You should try to get it by $scope.data. All directive inputs getting attached to your internal scope.
$attrs - is a hash object with key-value pairs of normalized attribute names and their corresponding attribute values. According to AngularJS docs.
Try this
var app = angular.module("myApp", []);
app.controller("prdController", function($scope) {
$scope.data = "krupesh";
$scope.stateChanged = function() {
$scope.data = "kotecha";
}
});
app.directive('myDir', function() {
return {
restrict: 'E',
template: "<div>{{data}}</div>"
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller=prdController as prd>
<my-dir data="prd.data" ng-click=stateChanged()></my-dir>
</div>
I built a directive that has checkboxes next to labels, inside a jQuery UI Accordion:
<ul class="checkbox-grid employee-info-tabs">
<li ng-repeat="column in columnsData">
<div class="styleAvailableColumns">
<input type="checkbox" ng-model="column.Selected" />
<label class="list-columns">{{ column.ColumnDisplayName }}</label>
</div>
</li>
</ul>
In my Controller, I want to be able to save the selected choices the user makes inside the directive, but I'm not sure how.
Here's my directive:
angular.module('component.column', [])
.directive('uiAccordion', function ($timeout, Columns, $location) {
return {
scope: {
columnsData: '=uiAccordion'
},
templateUrl: '/scripts/app/directives/test.html',
link: function (scope, element) {
var generateAccordion = function () {
$timeout(function () {
$(element).accordion({
header: "> div > h3",
collapsible: true,
active: 'none'
});
});
}
var loc = $location.absUrl();
var reportId = loc.substring(loc.lastIndexOf('/') + 1);
Columns.getAll(reportId).then(function (data) {
scope.columnsData = data;
generateAccordion();
}
Here's how I use the directive in my view <div ui-accordion="accordionData"></div>
I tried using scope: { '=' } but got Expression 'undefined' used with directive 'uiAccordion' is non-assignable!.
I've done some other googling, but I'm not 100% on the 'correct' direction on how to get this accomplished. If I can provide any other information, please let me know.
Set your directive scope to:
scope: {
columnsData: '='
},
Since you want the controller to maintain that data, your controller should have a reference to $scope.columnsData.
Then, on the view which is using the controller, you can feed that into the directive like so:
<div ui-accordion columns-data="columnsData"> </div>
Here's an example of your controller:
angular
.module('...')
.controller('myCtrl', ['$scope', function($scope) {
$scope.columnsData = "abcd123"
}]);
Try using your directive as:
<div ui-accordion="controllersColumnsData"></div>
where controllersColumnsData is a collection you can iterate in your controller whose items will have ColumnDisplayName and Selected properties set from your directive.
I am a bit struggling with infinite scroll in angular. I have one object array where all items are stored in. This object is part of directive controller.
Now when I am trying to implement infinite scroll I use separate directive to calculate offsets. I would like to access from this scroll directive variable from the other directive where object array is defined.
How can I do this? What would be the easiest way here? I am searching for week and can't find anything easy enough to implement to my solution.
Thank you
You could either use the directive's require property to get the $scope of another directive's controller, or use the parent controller of the directives to pass in a shared value. Here's an example using require (live demo).
<div ng-app="myApp">
<foo></foo>
<bar></bar>
</div>
angular.module('myApp', [])
.directive('foo', function() {
return {
controller: function($scope) {
$scope.foo = 123;
}
};
})
.directive('bar', function() {
return {
require: '^foo',
controller: function($scope) {
console.log($scope.foo);
}
};
})
;
The timing for this next example may not be what you want. They are sharing the same variable, but changes to $scope in the first directive's controller won't be applied until after the second directive's controller has already run. (live demo).
<div ng-app="myApp" ng-controller="MyCtrl">
{{sharedValue}}
<foo shared-value="sharedValue"></foo>
<bar shared-value="sharedValue"></bar>
</div>
angular.module('myApp', [])
.controller('MyCtrl', function($scope) {
$scope.sharedValue = 'abc';
})
.directive('foo', function() {
return {
scope: {
sharedValue: "="
},
controller: function($scope) {
console.log($scope.sharedValue); // abc
$scope.sharedValue = 123;
}
};
})
.directive('bar', function() {
return {
scope: {
sharedValue: '='
},
controller: function($scope) {
console.log($scope.sharedValue); // still abc, will update later
}
};
})
;
How can I use a different sets of initialization variables for each instance of controller in my app?
in view:
<div ng-controller="showProjectList">
{{project_list}}<!--user 1-->
</div>
<div ng-controller="showProjectList">
{{project_list}}<!--user 2-->
</div>
in controller
myapp.controller('showProjectList',function($http)
{ $scope.project_list= <Here I have a http request with argument user_id to fetch project_list>
}
Now how do I initialize each controller with a different user_id? One solution I have readon stackexchange & on google-groups is the use of ng-init.(link google-grp: https://groups.google.com/forum/#!topic/angular/J6DE8evSOBg) .However the use of ng-init is cautioned against in the same threads. So how do you initialize a controller with data then ?
You could use a combination of a controller, a directive and a service for that matter.
The controller is holding the user id's.
The directive is rendering the project list.
The service is responsible for fetching the data from the server. You could implement a cache and/or use $resource in here.
Here is the template code:
<div ng-controller="Projects">
<!-- here you can put an input element with
ng-model="users" to modify the user list on the fly -->
<div ng-repeat="user in users">
<project-list user="user" />
</div>
</div>
The controller:
myapp.controller('Projects', ['$scope', function($scope) {
$scope.users = [1, 2, 3];
}]);
The directive:
myapp.directive('projectList', ['UserService', function(UserService) {
return {
restrict: 'E',
scope: {
user: "="
},
templateUrl: 'project-list.html',
link: function($scope, $element, $attrs) {
UserService.getUserProject($scope.user).then(function(response) {
$scope.userProjects = response;
});
}
};
}]);
The service:
myapp.factory('UserService', ['$http', function($http) {
var getUserProject = function(user) {
var promise = $http.get('users/' + user + '/project');
return promise;
}
return {
getUserProject: getUserProject
}
}]);
I have set up the plunker to demonstrate the issue. The click of Bob button doesn't works. What I expected was, the child elements of the directive element will have the same isolated scope. Do I have to move the child elements into the template property of the directive?
I would define some object pass. Set up pass with method setDirectiveTitle and title:
Demo Plunker
JS
angular.module("myApp", [])
.directive("myScopedDirective", function() {
return {
scope: {
pass: '=',
preffix: "#msdTitle"
},
link: function($scope, $element, $attributes) {
$scope.pass.setDirectiveTitle = function(title) {
$scope.pass.title = $scope.preffix + title;
}
}
};
})
.controller("AppController", ["$scope", function($scope) {
$scope.passVal = {};
$scope.setAppTitle = function(title) {
$scope.passVal.title = title;
};
}]);
HTML
<div ng-controller="AppController">
<h2>{{title}}</h2>
<button ng-click="setAppTitle('App 2.0')">Upgrade Me!</button>
<div my-scoped-directive pass="passVal" msd-title="I'm a directive inside the app: {{passVal.title}}">
<h2>{{passVal.title}}</h2>
<button ng-click="passVal.setDirectiveTitle('Bob')" >Bob It!</button>
</div>
</div>
Problem is that is not compiled, you have to use transclusion in order to compile html inside a directive.
http://plnkr.co/edit/hGKeTqqU62Na0MWPvBIZ?p=preview
Or you can simply pass an template:
http://plnkr.co/edit/ZYhTdlwSDp0L3jjErOQt?p=preview
But you cannot use scope attribute binding in this case. Because on second update of parent scope , third click on child will not be updated as you expected.
You have to propagate data differently.