How can I have a two part attribute name with a directive? - angularjs

I have a directive:
app.directive("adminSelect", function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngChange: "&",
ngModel: "=",
options: "="
},
template: '<div><span>{{label}}</span><select id="{{id}}" ng-change="ngChange()" ng-model="ngModel" ng-options="item.id as item.name for item in options"></div>',
controller: function ($scope, $element, $attrs) {
$scope.label = $attrs.spanlabel;
$scope.id = $attrs.selectid;
}
};
});
I am calling this directive like this:
<div data-admin-select
spanlabel="ExamType"
selectid="examTypeSelect"
ng-change="ctrl.typeChanged(item)"
ng-model="ctrl.configService.admin.examTypeId"
options="ctrl.examType.dataPlus"></div>
The attribute names spanlabel and selectid are not really what I want. Can I make these into two part names like span-label of if not that spanLabel. If so then how can I do that?

http://jsbin.com/tugej/1/edit
html
<div data-admin-select
span-label="ExamType"
select-id="examTypeSelect"
ng-change="ctrl.typeChanged(item)"
ng-model="ctrl.configService.admin.examTypeId"
options="ctrl.examType.dataPlus">
</div>
js:
var app = angular.module('app', []);
app.directive("adminSelect", function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngChange: "&",
ngModel: "=",
options: "="
},
template: '<div><span>{{label}}</span><select id="{{id}}" ng-change="ngChange()" ng-model="ngModel" ng-options="item.id as item.name for item in options"></div>',
controller: function ($scope, $element, $attrs) {
$scope.label = $attrs.spanLabel;
$scope.id = $attrs.selectId;
}
};
});
app.controller('firstCtrl', function($scope){
})

Related

How can I access to ngModel of an input from a parent Directive / angularjs

I have this view
<div my-directive="somevalue">
<input name="myField" ng-model="dataForMyField">
</div>
And this is my directive
app.directive('myDirective', function ($compile) {
return {
restrict: 'A',
template: `<div ng-transclude=""></div>
<div>SomeValue from directive <strong>{{ someReturnedValue }}</strong></div>`,
transclude: true,
controller: function($scope, $element, $attrs, $transclude) {
$scope.someReturnedValue = 'ValueFromDirective';
console.log('Name of input'); // myField
$scope.$watch('vm.ngModel', function(newValue, oldValue, scope) {
console.log('WOW! Input.ngModel changed', newValue); // world in the init
});
}
}
})
How can I access to ngModel of input.
---------> here is a plkr: http://plnkr.co/edit/nWNAuf9jbv0sgY2VYRtZ?p=preview
Try this
<div my-directive="somevalue">
<input name="myField" ng-model="dataForMyField">
</div>
app.directive('myDirective', function () {
return {
scope: {
dataForMyField: '#dataAttr'
},
restrict: 'A',
template: `<div ng-transclude=""></div>
<div>SomeValue from directive <strong>{{ someReturnedValue }}</strong></div>`,
transclude: true,
controller: function($scope, $element, $attrs, $transclude) {
$scope.someReturnedValue = 'ValueFromDirective';
console.log('Name of input'); // myField
}
}
})

How to pass model variables from one directive to other using same controller for both directives?

Lets say i have a controller A:
app.controller('A', function($scope) {
$scope.commonvalue = "";
})
app.directive('dir1', function() {
return {
restrict: 'E',
templateUrl: 'template1.html',
controller: 'A'
};
});
app.directive('dir2', function() {
return {
restrict: 'E',
templateUrl: 'template2.html',
controller: 'A'
};
});
DIR1
template1.html:
<label>Enter value: </label>
<input ng-model="commonvalue"> </input>
DIR2
template2.html:
<p> The value of commonvalue variable is {{ commonvalue }} </p>
All i want to do is change the value of commonvalue from dir1 and get its value in dir2. One solution is to make the commonvalue variable in $rootScope. but i do not want to do that. I only want to change it in 'A' Controllers scope.
You can try something like this.
<div ng-app="myapp" ng-controller="myCtrl">
<my-changer ng-model="someVal"></my-changer>
<my-receiver ng-model="someVal"></my-receiver>
</div>
angular.module("myapp", [])
.controller("myCtrl", function($scope){
$scope.someVal = "Hello";
}).directive("myChanger", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
};
}).directive("myReceiver", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
}
});
JSFiddle
--EDIT---
If you are looking for one way binding then do this.
angular.module("myapp", [])
.controller("myCtrl", function($scope){
$scope.someVal = "Hello";
}).directive("myChanger", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<input type='text' ng-model='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
};
}).directive("myReceiver", function(){
return {
restrict: "E",
scope: {
txtVal : "=ngModel"
},
template: "<p ng-bind='txtVal'/>",
link: function(scope, elem, attr, ngModelCtrl){
}
}
});
Updated JSFiddle
what you want is actualy normal behavior.
when you dont specify a scope for your directive, it will inherit properties from its controller, and when ever a value changes it'll reflect back in the controller..
see this plnkr
app.controller('MainCtrl', function($scope) {
$scope.obj = {};
$scope.obj.commonvalue = "initial value";
});
app.directive('dir1', function() {
return {
restrict: 'A',
templateUrl: 'dir1.html'
}
})
app.directive('dir2', function() {
return {
restrict: 'A',
templateUrl: 'dir2.html'
}
})
I've updated the answer to use a 'dotted' ng-model, I think that was your issue at first. You can review my answer where it is explained why it's important.
from the answer:
What happens is that the child scope gets its own property that hides/shadows the parent property of the same name
You can define scope variable with '=' char in your directives and pass 'commonvalue' to them:
https://jsbin.com/fobofepuji/1/edit?html,js,output

My directive creates a <select> template. How can I make it call a function with the selected value when it changes?

I have this directive. Here is the simplified version with just the part that does not work:
app.directive("adminSelect", function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
ngChange: "&",
ngModel: "=",
options: "="
},
template: '<select ng-change="ngChange()" ng-model="ngModel" ng-options="item.id as item.name for item in options">',
controller: function ($scope, $element, $attrs) {
}
};
});
When I call this function like this:
<div admin-select
ng-change="ctrl.typeChanged()"
ng-model="ctrl.configService.admin.examTypeId"
options="ctrl.examType.dataPlus"></div>
How can I get the current value of the model and supply it into the ctrl.typeChanged() function?
I already tried this:
typeChanged = function () {
alert(self.configService.admin.examTypeId)
};
However it does not give the value that is just selected. It always alerts the previous value selected.
The value of the select will be stored in the scope variable that you set in its own ng-Model. Now, if what you want is to have a function that you want to get triggered when the value changes, just define that function in the controller of your directive, and call it from the ng-change of the select.
For example:
template: '<select ng-change="myChangeFunct()" ng-model="mySelectVal" ng-options="item.id as item.name for item in options">',
controller: function ($scope, $element, $attrs) {
$scope.myChangeFunct = function(){ alert($scope.mySelectVal); };
}
I would be a bit careful with the name of the attributes that you are using for your directive because they could conflict with the angular js directives.
Try with this in your directive definition:
app.directive("adminSelect", function () {
return {
restrict: 'A',
require: 'ngModel',
scope: {
adminChange: "&",
adminModel: "=",
adminOptions: "="
},
template: '<select ng-change="adminChange()" ng-model="adminModel" ng-options="item.id as item.name for item in adminOptions">',
controller: function ($scope, $element, $attrs) {
}
};
});
And this when you instantiate it:
<div admin-select
admin-change="ctrl.typeChanged()"
admin-model="ctrl.configService.admin.examTypeId"
admin-options="ctrl.examType.dataPlus"></div>

AngularJS - accessing parent directive properties from child directives

This should not be too hard a thing to do but I cannot figure out how best to do it.
I have a parent directive, like so:
directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
replace: true,
transclude: true,
template: '
<div class="editable-fieldset" ng-click="edit()">
<div ng-transclude></div>
...
</div>',
controller: ['$scope', function ($scope) {
$scope.edit = ->
$scope.editing = true
// ...
]
};
});
And a child directive:
.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
template: function (element, attrs) {
'<div>
<label>' + attrs.label + '</label>
<p>{{ model.' + attrs.field + ' }}</p>
...
</div>'
},
require: '^editableFieldset'
};
});
How can I easily access the model and editing properties of the parent directive from the child directive? In my link function I have access to the parent scope - should I use $watch to watch these properties?
Put together, what I'd like to have is:
<editable-fieldset model="myModel">
<editable-string label="Some Property" field="property"></editable-string>
<editable-string label="Some Property" field="property"></editable-string>
</editable-fieldset>
The idea is to have a set of fields displayed by default. If clicked on, they become inputs and can be edited.
Taking inspiration from this SO post, I've got a working solution here in this plunker.
I had to change quite a bit. I opted to have an isolated scope on the editableString as well because it was easier to bind in the correct values to the template. Otherwise, you are going to have to use compile or another method (like $transclude service).
Here is the result:
JS:
var myApp = angular.module('myApp', []);
myApp.controller('Ctrl', function($scope) {
$scope.myModel = { property1: 'hello1', property2: 'hello2' }
});
myApp.directive('editableFieldset', function () {
return {
restrict: 'E',
scope: {
model: '='
},
transclude: true,
replace: true,
template: '<div class="editable-fieldset" ng-click="edit()"><div ng-transclude></div></div>',
link: function(scope, element) {
scope.edit = function() {
scope.editing = true;
}
},
controller: ['$scope', function($scope) {
this.getModel = function() {
return $scope.model;
}
}]
};
});
myApp.directive('editableString', function () {
return {
restrict: 'E',
replace: true,
scope: {
label: '#',
field: '#'
},
template: '<div><label>{{ label }}</label><p>{{ model[field] }}</p></div>',
require: '^editableFieldset',
link: function(scope, element, attrs, ctrl) {
scope.model = ctrl.getModel();
}
};
});
HTML:
<body ng-controller="Ctrl">
<h1>Hello Plunker!</h1>
<editable-fieldset model="myModel">
<editable-string label="Some Property1:" field="property1"></editable-string>
<editable-string label="Some Property2:" field="property2"></editable-string>
</editable-fieldset>
</body>
You can get access to parent controller by passing attribute in child directive link function
link: function (scope, element, attrs, parentCtrl) {
parentCtrl.$scope.editing = true;
}

AngularJS - Share ngModel with nested directives and transcluded directives

I am trying to create 3 directives:
.directive('dirOne', function () {
return {
restrict: 'E',
transclude: true,
replace: true,
controller: function ($scope, $element, $attrs) {
this.add = function (tag) {
tag && $scope.tags.push(tag);
};
},
template: '<div><p>Bucket from directive: {{tags}}</p><div ng-transclude></div></div>'
};
})
.directive('dirTwo', function () {
return {
restrict: 'A',
replace: true,
require: '^dirOne',
link: function (scope, element, attrs, dirOne) {
scope.add = function (tag) {
dirOne.add(tag);
};
},
template: '<div>'+
' <input type="text" ng-model="query" datum="sugestions" dir-three>' +
' <button ng-click="add(query)">add</button>' +
'</div>'
};
})
.directive('dirThree', ['$compile', function ($compile) {
var itemsTemplate = '<span class="sugestions"><span ng-repeat="item in datum|filter:query">{{item.name||item}}</span></span>';
return {
restrict: 'A',
transclude: true,
replace: true,
require: 'ngModel',
scope: {
datum: '=',
query: '=ngModel'
},
link: function (scope, element, attrs) {
var parent;
element.wrap('<span>');
parent = element.parent();
parent.append(angular.element($compile(itemsTemplate)(scope)));
}
};
}])
In the dirTwo and dirThree, I have an input <input type="text" ng-model="query" datum="sugestions" dir-three> with ngModel, this input needs to access and modify the content of ngModel, so that the scope is not isolated.
http://jsfiddle.net/joaoneto/hbABU/3/
Update
I Updated version, fix some mistakes I had committed, the content that was being transcluded in dirTwo, should not have the "ADD" function, and belongs to dirTree, hope it helps someone and apologize for peopl take to update this entry... see in http://jsfiddle.net/hbABU/4/

Resources