I have created an directive with isolated scope named <student>, everything is working fine am able to pass different data to my directive using isolated scope "=". But am not able to save the changes in the data.
code:
<div ng-app="mainApp" >
<div layout="column" flex ng-controller="StudentController">
<student operation="productadd"></student>
<button type="submit" ng-click="submit()">click</button>
<div style="float:left;background:#ccc;">
<!--<student operation="productmodify"></student>-->
</div>
</div>
</div>
app.js
var mainApp = angular.module("mainApp", ['ngMaterial']);
mainApp.controller('StudentController', ['$scope', '$mdDialog', function ($scope, $mdDialog) {
$scope.productadd = {};
$scope.productadd.colors = ['#a55466', '#8298a6', '#586a75', '#af1e2c', '#b3995d', '#7fc7af',
'#afb4bb', '#b9adad', '#899a9f', '#7d7d7d', '#525252', '#636c6f',
'#347d7b', '#b1b1b1', '#53748c', '#927f92', '#695769', '#a07c7c', '#6f7d86',
'#94b1c4', '#24122a', '#6c6169', '#6d5656', '#d19898', '#ac7c7c', '#aaaaaa',
'#bbcccc', '#999999', '#ccbbbb', '#779999', '#cdc1c5', '#8b8386'];
$scope.productadd.uomList = ['oz1', 'mm2', 'meter3'];
$scope.productadd.merchList = ['hand', 'tray', 'case', 'basket'];
$scope.productadd.nameList = ['Unit', 'Case', 'TRAY', 'Pallet 4 layers', 'Half Pallet 3 layers', ' Half Pallet 4 layers', ' Cut Case 24', 'Pallet 3 layers', 'Cut Case 12'];
$scope.productadd.orientationList = ['Front End', 'Front Side', 'Side End', 'Side Front', 'End Front', 'End Side'];
$scope.productadd.distributerTypeList = ['WHS', 'DSP', 'DSB', 'DSA', 'DSS', 'DSD'];
$scope.productmodify = {};
$scope.productmodify.colors = ['#a55466', '#8298a6'];
$scope.productmodify.uomList = ['oz', 'mm', 'meter'];
$scope.productmodify.merchList = ['hand', 'tray', 'case', 'basket'];
$scope.productmodify.nameList = ['Unit', 'Case', 'TRAY', 'Pallet 4 layers', 'Half Pallet 3 layers', ' Half Pallet 4 layers', ' Cut Case 24', 'Pallet 3 layers', 'Cut Case 12'];
$scope.productmodify.orientationList = ['Front End', 'Front Side', 'Side End', 'Side Front', 'End Front', 'End Side'];
$scope.productmodify.distributerTypeList = ['WHS', 'DSP', 'DSB', 'DSA', 'DSS', 'DSD'];
$scope.submit = function () {
console.log($scope.product);
}
}]);
mainApp.directive('student', function () {
return {
restrict: 'E',
templateUrl:'temp.html',
scope: {
productedit: "=operation"
},
}
});
examplecode
I have added an submit and am trying to save my model named product. But am getting undefined.
Please guide me how to solve this problem.
The way you have currently have your html structure, you have placed your submit form button outside the directive template. For solving this issue, basically you are just passing the value of dropdowns. So i'd suggest you to pass the value of product object which would be initially {} & that will be modified by the directive template.
HTML
<student operation="productadd" product="product"></student>
Controller
$scope.product = {}; //initially blank, filled up by directive.
Directive
mainApp.directive('student', function() {
return {
restrict: 'E',
templateUrl: 'temp.html',
scope: {
productedit: "=operation",
product: '=' //pass product object here
},
}
});
Demo Plunkr
$scope.submit = function () {
console.log($scope.product);
};
It logs an undefined scope property so it will never save any changes anywhere
mainApp.directive('student', function () {
return {
restrict: 'E',
templateUrl: 'temp.html',
scope: {
productedit: "=operation"
},
}
});
Should not have , after scope property (it's the last property on that object),
Where is your controller/link function?
You should move productadd to a service.
Related
I have the following code, which is trying to add a variable to the $rootScope through a directive and trying to get that value and show it inside a controller element.
But when I click the links inside the directive, it doesn't display the new $rootScope variable.
https://plnkr.co/edit/P7Lq7h13RmXryFC0uBMi?p=info
var mod = angular.module('myApp', []);
mod.directive('mainMenu', menuDirec);
function menuDirec($rootScope){
return {
templateUrl: 'menu.html',
restrict: 'A',
controller: menuControl,
controllerAs: 'vm'
};
function menuControl(){
var vm = this;
vm.menu = {
'one': 'Link 1',
'two': 'Link 2',
'three': 'Link 3',
'four': 'Link 4'
};
vm.clickMenu = function(slug){
$rootScope.active = slug;
console.log($rootScope);
console.log(slug);
}
}
}
mod.controller('content', contentControl);
function contentControl($scope, $rootScope){
$scope.title = $rootScope.active;
}
Change the HTML to access the title as a function
<div ng-controller="content">
<h1>{{ title() }}</h1>
</div>
In your JS make it a function
mod.controller('content', contentControl);
function contentControl($scope, $rootScope){
$scope.title = function () {
return $scope.active;
};
}
Then on each digest cycle, the $watch attached to the {{title()}} will execute the function and update the DOM as the value of $scope.active changes.
The UPDATE on PLNKR.
Best practice
Avoid cluttering $rootScope with variables. Instead use isolate scope and two-way binding. For more information, see AngularJS Comprehensive Directive API - scope.
As example
mod.directive('mainMenu', menuDirec);
function menuDirec(){
return {
templateUrl: 'menu.html',
restrict: 'A',
controller: menuControl,
controllerAs: 'vm',
scope: { active: '=' },
bindToController: true
};
function menuControl(){
var vm = this;
vm.menu = {
'one': 'Link 1',
'two': 'Link 2',
'three': 'Link 3',
'four': 'Link 4'
};
vm.clickMenu = function(slug){
vm.active = slug;
console.log(slug);
}
}
}
HTML
<body ng-app="myApp">
<nav main-menu active="title"></nav>
<div ng-controller="content">
<h1>{{ title }}</h1>
</div>
</body>
The DEMO on PLNKR
OK, so I have a directive which takes attributes and reads it (and writes it out).
Here is the plunker: http://embed.plnkr.co/IkKPLahPc9yqeHWEQUG3/
I think it's because of the controller: ctrl inside main-directive.js which has nothing whereas the actual action is happening inside the isolated directive's controller controller.
Here is the main-directive.js:
var app = angular.module('testapp.directive.main', ['main']);
app.directive('myCustomer', function() {
var controller = ['$scope', function($scope) {
$scope.dan = { 'name': 'Dan', 'nationality': 'ESP' };
// scope from here obv...
}];
var template = 'Getting attribute value of =getInfo... {{getInfo.name}} from {{getInfo.nationality}}';
return {
restrict: 'E',
controller: controller,
scope: {
getInfo: "=info"
},
template: template
};
});
app.controller('ctrl', function($scope) {
})
and here's my template:
<div ng-controller="ctrl">
<my-customer info="dan">
</my-customer>
</div>
Why is my directive not reading the attribute of info?
You're right, the $scope.dan object needs to be in the ‘ctrl’ controller scope and pulled out of the isolate directives controller scope.
app.controller('ctrl', function($scope) {
$scope.dan = { 'name': 'Dan', 'nationality': 'ESP' };
})
This is applicable to the method of two-way data binding that you have set up for getInfo used by "=info"
The way that is coded, it is expecting the ctrl controller to have a property called "dan" on its scope. If you are just passing in the string 'dan', you want to change your directive to use # instead of =
app.directive('myCustomer', function () {
var controller = ['$scope', function ($scope) {
$scope.dan = {'name': 'Dan', 'nationality': 'ESP'};
// scope from here obv...
}];
var template = 'Getting attribute value of =getInfo... {{getInfo.name}} from {{getInfo.nationality}}';
return {
restrict: 'E',
controller: controller,
scope: {
getInfo: "#info" //<--NOTE THE CHANGE HERE
},
template: template
};
});
I am building a dropdown menu directive which allows you to optionally attach a function to each item in the list. I know how to pass one function per attribute into the directive, but I'm hoping that there is a way to pass multiple functions.
<dropdown items="['item1', 'item2']" actions="['action1()', 'action2()']"></dropdown>
or better yet:
<dropdown items="[{'item1':action1()}, {'item2':action2()}]"></dropdown>
which could be used to generate:
<dropdown items="['item1', 'item2']" actions="['action1()', 'action2()']">
<a ng-click="action1()">item1</a>
<a ng-click="action2()">item2</a>
</dropdown>
You can use the = object notation for your scope in accepting an array of objects with properties that you can assign to your directive.
DEMO
Controller
.controller('Ctrl', function($scope) {
var action = function() {
window.alert(this.label);
};
$scope.items = [{
label: 'Item 1',
action: action
}, {
label: 'Item 2',
action: action
}, {
label: 'Item 3',
action: action
}, {
label: 'Item 4',
action: action
}];
})
Directive
.directive('dropdown', function() {
return {
restrict: 'E',
scope: {
items: '='
},
template:
'<div ng-repeat="item in items track by $index" ng-click="item.action()">' +
'<a ng-bind="item.label"></a>' +
'</div>'
};
});
index.html
<body ng-controller="Ctrl">
<dropdown items="items"></dropdown>
</body>
to pass any form of function to a directive that does same thing in thesense ike a call back from the directive to execute the function , the method should be as below
First of all use the return scope to contain the functionName : '&' as it is used in passing functions
Then returning it back should look like this from ur template ng-click='functionName({params:values[,params2:value2]})'
as the above would send the param as argument to the calling controller calling the directive
var app = angular.module('testApp', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.items=['value1','value2','value3'];
$scope.items2=['value12','value22','value32'];
$scope.clicked='';
$scope.alert=function(val){
$scope.clicked=val;
}
$scope.alerti=function(val){
$scope.clicked=val+"-Second";
}
});
app.directive('direct', function(){
return {
restrict: 'E',
scope : {
actionTest:'&',
tests:'='
},
// controller: 'ctrl',
template: '<ul><li ng-repeat="test in tests" ng-click="actionTest({val:test})">{{test}} </li></ul>'
}
});
/*
app.controller('ctrl', function($scope){
});*/
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="testApp">
<div ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<p>CLicked : {{clicked}}</p>
<direct tests='items' action-test='alert(val)'></direct>
<!--with a different action function-->
<direct tests='items2' action-test='alerti(val)'></direct>
</div>
</div>
I have a specific scenario for a AngularJS directive:
Normally the directive should inherit the default scope
But for some specific scenarios I'd like to replace all values in $scope.myValues with myValues (object loaded from a web-service)
I cannot change in this scenario the main-scope because this is owned by another application (more or less a plugin-mechanism).
Thanks & Regards
Stefan
If think I have found the solution:
Sample Html:
<wi-view data-layout="{{passLayout}}"></wi-view>
<hr />
Original property: {{layout.property1}}
Sample Controller:
app.controller('wiController', function($scope) {
// Simulating the original scope values
$scope.layout = {};
$scope.layout.property1 = 'Original Value';
// New scope values, just here for binding it to the controller
var passLayout = {};
passLayout.property1 = 'Value Overwritten';
passLayout.property2 = 'Another Property';
$scope.passLayout = passLayout;
});
Sample Directive:
app.directive('wiView', function () {
var linkFunction = function(scope, elems, attrs) {
if (attrs.layout !== undefined) {
scope.layout = angular.fromJson(attrs.layout);
}
};
return {
restrict: "E",
scope: true,
priority: 0,
link: linkFunction,
template: '<div>Hello, {{layout.property1}}!</div>'
};
});
I have a fiddle at http://jsfiddle.net/skwidgets/w2X9m/3/ to build out a group of check boxes. It works just as desired in the prototype and I can even include more then one group and they run independently. As I was satisfied I add the code to the app that I am building and the html in the template: '<>' of the directive does not appear. the model data that is in the handle bars in the template does how ever. I cannot seam to figure out why as there are not errors.
I also have this plunker that shows the code working
http://plnkr.co/edit/JE5dRDU4VyGd0UAbCtNu?p=preview
<div class="sqs" >
<pre>
{{survey | json}}
</pre>
<suvey-checkbox ng-model="Q1" ng-init="surveyQuestions = [
{ 'value':'value1', 'name': 'The unit' },
{ 'value': 'value2', 'name': 'Patient Threw Up'},
{ 'value':'value3', 'name': 'Unsafe for children' },
{ 'value':'value4', 'name': 'Actively dying, reached life goal'}]">
</suvey-checkbox>
<suvey-checkbox ng-model="Q2" ng-init="surveyQuestions = [
{ 'value':'value1', 'name': 'The unit' },
{ 'value': 'value2', 'name': 'Patient Threw Up'},
{ 'value':'value3', 'name': 'Unsafe for children' },
{ 'value':'value4', 'name': 'Actively dying, reached life goal'}]">
</suvey-checkbox>
</div>
And
var app = angular.module("app", []);
app.run(function($rootScope){
$rootScope.survey = [];
});
app.directive('suveyCheckbox', function ($rootScope) {
return {
restrict: 'E',
require: '^ngModel',
scope: {
ngModel: '#'
},
template: '{{ngModel}}<br /><label ng-repeat="surveyQuestion in surveyQuestions" class="checkbox">' +
'<input data-role="none" type="checkbox" name="selectedExclusion[]" value="{{surveyQuestion.value}}"' +
'ng-checked="surveyAnswers.indexOf(surveyQuestion.value) > -1" ng-click="togglesurveyAnswers(surveyQuestion.value)"> ' +
'{{surveyQuestion.name}} <br /></label>{{surveyAnswers}}',
link: function (scope, elem, attr) {
// selected exclusion
scope.surveyAnswers = [];
// toggle surveyAnswers for a given answer by name
scope.togglesurveyAnswers = function togglesurveyAnswers(surveyQuestion) {
var idx = scope.surveyAnswers.indexOf(surveyQuestion);
// is currently selected
if (idx > -1) {
scope.surveyAnswers.splice(idx, 1);
}
// is newly selected
else {
scope.surveyAnswers.push(surveyQuestion);
}
};
$rootScope.survey.push(scope.surveyAnswers);
}
}
});
I took the code from the prototype in the fiddler that is linked and that is not working for some reason.
The code will not work in newer versions of angular. In previous versions there was a bug that caused isolate scope to not be really isolate and leak out to other directives.
In angular 1.2.x isolate scope is truly isolate. This means that you cannot use anything in your template unless the directive either put it manually into the scope or it is included in the isolate scope definition (e.g. scope: { myVar: '='})
For example, in your case your template cannot access surveyQuestions because it was not defined in the private scope (ng-init will not be able to access the isolate scope inside of your surveyCheckbox directive.
If you want to be able to use surveyQuestions in your directive's template you need to pass it in to the isolate scope:
<survey-checkbox questions="surveyQuestions" ng-model="bedsideQ2" ng-init="surveyQuestions = [
{ 'value':'value1', 'name': 'The unit' },
{ 'value': 'value2', 'name': 'Patient Threw Up'},
{ 'value':'value3', 'name': 'Unsafe for children' },
{ 'value':'value4', 'name': 'Actively dying, reached life goal'}]">
</survey-checkbox>
And then add it to your isolate scope:
scope: {
ngModel: '#',
surveyQuestions: '=questions'
}