Angular 1.5.8 input custom directive ng-model - javascript

I've been struggling and Googling everywhere around and I can't imagine why this directive doesn't update my controller $scope value:
Directive:
app.directive('ingFormField', function () {
return {
restrict: "E",
scope: {
value: "=",
fieldName: "#",
fieldLabel: "#"
},
div class="form-group">'+
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>'+
' <input ng-model="value" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
});
used in HTML:
<ing-form-field field-name="Order" field-label="Order" ng-model="lateral.Order"></ing-form-field>
And my object "lateral" from my controller:
$scope.lateral = {Order: "01", Name: "Person"}
I've tried some functions from StackOverflow answers about using a link function to update values in my controller $scope with the same output: values from $scope to the directive are working but any change on the directive's input field don't update $scope object "lateral"

This may be has an alternative aproach by using ngModel parameter directly and pass it through your template. Using ngModel will help you to keep consistence of naming things on your template.
For example, if you use your directive template using the ngModel directive, you can call it from the directive scope and use it do reflect the model to your parent controller.
The following code implement this solution, be aware that this is one of the solution, you may find different ways to do that.
angular
.module('myApp', [])
.directive('ingFormField', function() {
return {
restrict: "E",
scope: {
ngModel: "=",
fieldName: "#",
fieldLabel: "#"
},
template: '<div class="form-group">' +
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>' +
' <input ng-model="ngModel" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
})
.controller('myController', function($scope) {
$scope.lateral = {
Order: "01",
Name: "Person"
}
});
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-controller="myController">
<ing-form-field field-name="Order" field-label="Order" ng-model="lateral.Order">
</ing-form-field>
<pre>{{ lateral | json }}</pre>
</div>

Please see below code, you're very close. I think you may have been trying to set/pass the value using ngModel instead of the scoped property you designated for it, which was value. That's if I'm understanding correctly. Please let me know if this helps, if not I can always update.
function exampleController($scope) {
$scope.lateral = {
Order: "01",
Name: "Person"
};
}
function ingFormField() {
return {
restrict: "E",
scope: {
value: "=",
fieldName: "#",
fieldLabel: "#"
},
template: '<div class="form-group"> ' +
' <label for="{{fieldName}}" class="control-label">{{fieldLabel}}:</label>' +
' <input ng-model="value" class="form-control" type="text" name="{{fieldName}}" id="{{fieldName}}" />' +
'</div>'
};
}
angular
.module('example', [])
.controller('exampleController', exampleController)
.directive('ingFormField', ingFormField);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div class="container-fluid" ng-app="example">
<div class="container" ng-controller="exampleController">
<ing-form-field field-name="Order" field-label="Order" value="lateral.Order"></ing-form-field>
</div>
</div>

Related

Set ng-model and class property inside a directive template

I am trying to create a simple directive to make my html page abit slimmer. I want to pass down properties to the directive template and set properties.
The problem is when i am trying to pass a string and set the ng-model property and class property in the template. All the other properties i pass down work fine its just the class and ng-model property that doesnt work.
How can i set the ng-model and class property in my template by just passing down a string to them?
controller:
angular.module('app.sst').directive('inputDirective', function () {
return {
scope: {
colWidth: '#',
label: '#',
type: '#',
name: '#',
ngModel: '='
},
templateUrl: 'components/blocks/directives/inputTemplate.html',
};
});
directive template:
<div class="{{colWidth}}">
<label>{{label}}</label>
<div class="field">
<input type="{{type}}"
name="{{name}}"
ng-model="ngModel"
class="form-control inputText" />
</div>
</div>
index:
<div input-directive
colWidth="col-md-4"
label="Proceded by"
type="text"
name="procededBy"
ng-model="vm.SSTItem.procededBy">
</div>
Two things to take note here:
1) Make ngModel required.
2) Do not use ngModel in isolated scope the way you are using now as angular might get confused for the key instead use meaningful name like below.
angular.module('app', [])
.directive('inputDirective', function(){
return {
required: '^ngModel',
scope: {
modelName: "=ngModel"
},
template: '<input type="text" ng-model="modelName">'
};
})
See plunk.

Cannot get '&' prefix working when defining isolated scope in basic angular directive

I'm boning up on Angular directives and having trouble with the isolated scope. I'm making a VERY basic directive/controller and simply trying to throw an alert on an ng-click from within a directive by setting a scope attribute to the '&' prefix. I've been staring at this for 45 minutes now and can't see what I'm doing wrong, but nothing is happening when clicking the button (the other 2 prefixes are working though). Here is the code for the directive/controller:
(function() {
'use strict';
angular
.module('mePracticing')
.directive('practiceDirective', practiceDirective);
function practiceDirective() {
var directive = {
restrict: 'AE',
scope: {
movie: '=',
rating: '#',
display: '&'
},
template: '<div>Movie: {{movie}}</div>' +
"Enter a movie: <input type ='text' ng-model='movie'>" +
"<div>Rating: {{rating}}</div>" +
"<div><button ng-click='displayMovie(movie)'>CLICK ME</button></div>"
};
return directive;
}
})();
(function() {
'use strict';
angular
.module('mePracticing')
.controller('practiceController', practiceController);
function practiceController($scope) {
$scope.movie = 'The Big Lebowski';
$scope.rating = 1000101010;
$scope.displayMovie = function(movie) {
alert("Movie :" + movie);
}
}
})();
And here is the HTML:
<html>
<head>
<title>Directive Practice</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body ng-app="mePracticing">
<h1>HEADER</h1>
<div ng-controller="practiceController">
<practice-directive movie="movie" display="display(movie)" rating="{{rating}}"></practice-directive>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="app.js"></script>
<script src="myDirective.js"></script>
</body>
</html>
The app.js is just one line where I create my module:
angular.module('mePracticing', []);
If anyone can give me any tips on why that '&' isn't working I'd really appreciate it. Thank you!
EDIT: I made a JSFiddle for it: https://jsfiddle.net/hozxz5n4/
It occurs because when you are using the directive there is not a function called "display", you need to pass the declared function:
<practice-directive movie="movie" display="displayMovie(movie)" rating="{{rating}}"></practice-directive>
and finally in the directive just call display prop function:
(function() {
'use strict';
angular
.module('mePracticing')
.directive('practiceDirective', practiceDirective);
function practiceDirective() {
var directive = {
restrict: 'AE',
scope: {
movie: '=',
rating: '#',
display: '&'
},
template: '<div>Movie: {{movie}}</div>' +
"Enter a movie: <input type ='text' ng-model='movie'>" +
"<div>Rating: {{rating}}</div>" +
"<div><button ng-click='display()'>CLICK ME</button></div>"
};
return directive;
}
})();
The directive has its own isolated scope, so your displayMovie() function introduced in the practiceController never get's called. Move the function to your directive like so:
function practiceDirective() {
var directive = {
restrict: 'AE',
scope: {
movie: '=',
rating: '#',
display: '&'
},
link: function(scope, element, attrs) {
scope.displayMovie = function(movie) {
alert("Movie :" + movie);
}
},
template: '<div>Movie: {{movie}}</div>' +
"Enter a movie: <input type ='text' ng-model='movie'>" +
"<div>Rating: {{rating}}</div>" +
"<div><button ng-click='displayMovie(movie)'>CLICK ME</button></div>"
};
return directive;
}
Working fiddle:
https://jsfiddle.net/hozxz5n4/1/
Also take a look at this great answer.

Dynamic model binding in nested directives working for input values, but not select

I have a custom directive being used like so:
<drop-down-filter-field
model="my_model.property"
options="{ list: property_options, field: 'code' }"
></drop-down-filter-field>
With the directive code (field is another directive that groups together some common markup for errors and layout etc):
<field label="label" field="field" model="model" display="display" annotation="annotation">
<select
ng-model="$parent.model"
ng-change="setValue(item.value, item[options.field])"
>
<option ng-repeat="item in options.list" value="{{item.value}}">{{item[options.field]}}</option>
</select>
</field>
I tried to add the ng-change to manually set my model value, since the drop down isn't working. But, the function in ng-chang isn't firing either.
And Directive
angular.module('my-app')
.directive('dropDownFilterField', function($compile) {
return {
restrict: 'E',
templateUrl: 'views/directives/form-elements/drop-down-filter-field.html',
controller: 'dropDownFilterField',
scope: {
model: '=',
label: '=',
field: '=',
options: '=',
annotation: '=',
}
};
})
.controller('dropDownFilterField', function($scope, $element, $parse) {
$scope.setValue = function(value) {
self.$scope.model = value;
};
})
;
I already have this pattern with the nested directive with "$parent.model", functioning in several other templates/directives, for example, an input tag:
<field label="label" field="field" model="model" annotation="annotation" validate="validate">
<input type="text" name="{{formname}}" ng-model="$parent.model" ng-required="{{required}}" placeholder="{{field.default}}"
uib-typeahead="{{'typeAheadItem' + (options.field ? '.' + options.field : '')}} as {{'typeAheadItem' + (options.field ? '.' + options.field : '')}} for typeAheadItem in options.list | filter:$viewValue | limitTo:{{options.limit || 8}}"
ui-validate="'validateFunction($value)'"/>
</field>
All of my other custom directives that contain inputs, and textareas are working, but I can't get it working for select. Anyone know why this might be ?
Have you tried using ng-options?
<select
ng-model="$parent.model"
ng-options="item.value as item[options.field] for item in options.list"
>
</select>
There should be no need to use ng-change to update ng-model value, the two-way-binding of ng-model should update itself.

Angular directive - isolated scope isn't showing

I trying to make a directive which accepting an attribute and hook it to the isolated scope, but the attribute value is not showing.
angular.module('app', [])
.controller('torrentController', [function() {
this.recommended = ['...'],
this.otherArray = ['...']
}])
.directive('torrentsTable', [function() {
return {
restrict: 'E',
templateUrl: 'templates/directives/torrentsTable.html',
scope: {
index: '='
},
controller: 'torrentController as torrentCtrl'
};
}]);
The idea is to use this directive to show different list of torrents with this syntax:
<torrents-table index="recommended"></torrents-table>
<torrents-table index="someOtherIndex"></torrents-table>
I wish this 2 almost same lines to show different "list" with results.
templates/directives/torrentsTable.html
<!-- I also tried with ng-repeat="torrent in torrentCtrl.recommended" -->
<!-- And is working as I excepted (It's shows the recommended array) -->
<div layout="row" ng-repeat="torrent in torrentCtrl[index]">
<div flex>Name: {{torrent.name}}</div>
<div flex>{{index}}</div>
</div>
{{index}} is not showing, and it's value is not showing.
While I actually make hardcoded ng-repeat arguments - it repeating but {{index}} is empty.
What I am doing wrong?
Your problem: how you pass key.
You use in directive:
scope: {
index: '='
},
so you should pass to directive expression, that evaluated to $scope property. So if you not inject scope - you pass undefined.
You can fix this two ways:
1) pass string instead something else
<torrents-table index="'recommended'"></torrents-table>
<torrents-table index="'someOtherIndex'"></torrents-table>
2) change directive definition to
scope: {
index: '#'
},
sample you can see in snippet below.
angular.module('app', [])
.controller('torrentController', [function() {
this.recommended = [1,2,3,4,5];
this.someOtherIndex = ['a','b','c','d','e'];
}])
.directive('torrentsTable', [function() {
return {
restrict: 'E',
template: '<div flex>{{index}}</div>'+
'<div layout="row" ng-repeat="torrent in torrentCtrl[index]">'+
' <div flex>Name: {{torrent}}</div>'+
'</div>',
scope: {
index: '='
},
controller: 'torrentController as torrentCtrl'
};
}])
.directive('torrentsTable2', [function() {
return {
restrict: 'E',
template: '<div flex>{{index}}</div>'+
'<div layout="row" ng-repeat="torrent in torrentCtrl[index]">'+
' <div flex>Name: {{torrent}}</div>'+
'</div>',
scope: {
index: '#'
},
controller: 'torrentController as torrentCtrl'
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
<div ng-app='app'>
<torrents-table index="'recommended'"></torrents-table>
<torrents-table index="'someOtherIndex'"></torrents-table>
<hr/>
<torrents-table2 index="recommended"></torrents-table2>
<torrents-table2 index="someOtherIndex"></torrents-table2>
</div>

AngularJS: Passing object property name to directive

I'm writing an angular.js directive that is a reusable input component for an array of objects.
Since it is impossible to use primitive values in ng-repeat (see: What is the angularjs way to databind many inputs?), I have to pass an array of objects to the component:
In the controller I initialize:
$scope.theSimpsons = [{ value: 'Bart' }, { value: 'Lisa' }];
And then use it in the HTML file:
<div ng-app="App">
<div ng-controller="AppCtrl">
<multi-input items="theSimpsons" />
</div>
</div>
The directive itself is implemented like this:
directive('multiInput', function () {
return {
restrict: 'E',
scope: {
items: '=items'
},
template:
'<div>' +
'<div ng-repeat="item in items">' +
'<input type="text" ng-model="item.value">' +
'<a ng-click="items.splice($index, 1)">remove</a>' +
'</div>' +
'<a ng-click="items.push({value:\'\'})">add</a>' +
'</div>'
};
});
This is all working good.
My question: what if the objects don't have a value?
This directive codes the name of the property (value) hard. But what, if I want to have an array like this: [{ name: 'Bart' }, { name: 'Lisa' }].
Is it possible to pass the name of the object, e.g. like
<multi-input items="names" property="name"></multi-input>
and use it somehow in the directive to access the name property?
Here is the JSFiddle http://jsfiddle.net/napU6/5/ I have created to show this directive.
Use another attribute to pass the name of the property
<multi-input items="myItems" name="value"></multi-input>
Directive
app.directive('multiInput', function(){
return {
restrict: 'E',
replace: true,
scope: {
items:'=',
name: '#'
},
template:'<div>'
+ '<div ng-repeat="item in items">'
+ '<input type="text" ng-model="item[name]">'
+ '<a ng-click="items.splice($index, 1)">remove</a>'
+ '</div>'
+ '<a ng-click="items.push({})">add</a>'
+ '</div>'
}
});
Demo: Plunker

Categories

Resources