angular 1.4 directive toggle view - angularjs

I want to show two different inputs depending on a toggle attribute.
No I have the problem that I should define each attribute/property of the input in my directive, but the binding doesn't work.
Directive:
angular.module('directive')
.directive('inputBlock', function () {
return {
restrict: 'AEC',
replace: true,
scope: {
model: '=',
modernStyle:'=',
name:'=',
type:'=',
label:'='
},
link: function (scope, elem, attrs, ctrl) {},
templateUrl: 'views/templates/inputBlockTemplate.html'
};
});
Template:
<div>
<div ng-if="!modernStyle">
<label>{{label}}</label>
<input ng-model="model" name="{{name}}" type="{{type}}"/>
</div>
<md-input-container ng-if="modernStyle">
<label>{{label}}</label>
<input ng-model="model" name="{{name}}" type=" {{type}}"/>
</md-input-container>
</div>
Usage:
<input-block model="name" label="'firstname'" modern-style="true" name="'firstname'" type="'text'">
</input-block>
Is it possible to do something like a toggle in directives?
Furthermore is it possible to redirect the bindings to directives?

ng-if creates a new child scope, try change by ng-show/ng-hide
Understanding Scopes
Other considerations:
As you use name,label and type as text inside your directive is not necesary that it will be binding, I recomend use # instead of =, or access it directly from the attrs link argument.
The scope.model could be set as ngModel to use the default angular directive.
Javascript:
angular.module("directive").directive("inputBlock", function () {
return {
restrict: "AEC",
replace: true,
scope: {
ngModel: "=",
modernStyle:"#",
//name:"#",
//type:"#",
//label:"#"
},
link: function (scope, elem, attrs, ctrl) {
scope.type=attrs.type;
scope.name=attrs.name;
scope.label=attrs.label;
},
templateUrl: "views/templates/inputBlockTemplate.html"
};
});
Template:
<div>
<div ng-show="!scope.modernStyle">
<label>{{scope.label}}</label>
<input ng-model="scope.model" name="{{scope.name}}" type="{{scope.type}}"/>
</div>
<md-input-container ng-show="scope.modernStyle">
<label>{{scope.label}}</label>
<input ng-model="scope.model" name="{{scope.name}}" type={{scope.type}}"/>
</md-input-container>
</div>
Usage:
<input-block ng-model="name" label="firstname" modern-style="true" name="firstname" type="text">
</input-block>

Related

AngularJS custom form component / directive using ng-model

Angular custom form component / directive and $dirty property
When using regular input, such as
<form name="myForm">
<input type="text" ng-model="foobar">
</form>
after typing in the input box myForm.$dirty is true.
I'd like to create a simple directive such as
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
scope: {
fooBar: '='
},
template: '<div><button ng-click="fooBar=foo"></button><button ng-click="fooBar=bar"></button></div>'
};
});
Sample usage would be
<form name="myForm">
<my-directive foo-bar="myObj.foobarValue"></my-directive>
</form>
and after user clicks on any of the two buttons, myForm$dirty is set to true.
How is this accomplished?
Implementing custom form controls (using ngModel)
Use the ngModel controller and the object form of the require property in the DDO:
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
require: { ngModelCtrl: 'ngModel' },
scope: {
ngModel: '<'
},
bindToController: true,
controllerAs: '$ctrl',
template:
`<div>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('foo')">
Set foo
</button>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('bar')">
Set bar
</button>
</div>`,
controller: function ctrl() {}
};
});
Usage:
<form name="myForm">
<input type="text" ng-model="foobar">
<my-directive ng-model="foobar"></my-directive>
</form>
By instantiating and using the ng-model controller, the directive will automatically set the form controls as necessary.
The DEMO
angular.module('myModule', [])
.directive('myDirective', function() {
return {
restrict: 'E',
require: { ngModelCtrl: 'ngModel' },
scope: {
ngModel: '<'
},
bindToController: true,
controllerAs: '$ctrl',
template:
`<div>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('foo')">
Set foo
</button>
<button ng-click="$ctrl.ngModelCtrl.$setViewValue('bar')">
Set bar
</button>
</div>`,
controller: function ctrl() {}
};
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myModule">
<h2>ngModel DEMO</h2>
<form name="myForm">
<input type="text" ng-model="foobar">
<my-directive ng-model="foobar"></my-directive>
</form>
<br>myForm.$dirty = {{myForm.$dirty}}
<br>myForm.$pristine = {{myForm.$pristine}}
<br><button ng-click="myForm.$setDirty()">Set dirty</button>
<br><button ng-click="myForm.$setPristine()">Set pristine</button>
</body>
I recommend isolate scope with ngModel as an input. Output should be done with the $setViewValue method.
For more information, see
AngularJS Developer Guide - Implementing custom form controls (using ngModel)
AngularJS Developer Guide - Component-based application architecture

Decorating AngularJS Directive template inside the directive

I have a directive which is defined, say, as below:
angular.module('some-module').directive('someDirective', function() {
return {
restrict: 'E',
replace: 'true',
templateUrl: 'some-template.html',
link: link,
require: '^form',
transclude: true,
scope: {
decorate: '=',
}
};
});
Let's say this is how the some-template.html looks (there is more in the actual template though):
<div ng-transclude></div>
And this is how I will use the directive:
<some-directive decorate="true">
<input name="x" type="number" ng-model="x">
<input name="y" type="number" ng-model="y">
</some-directive>
<some-directive decorate="false">
<input name="a" type="number" ng-model="a">
<input name="b" type="number" ng-model="b">
</some-directive>
What I want the directive to do is to manipulate the DOM so that if decorate is true then, the two input fields should be decorated with some divs as below:
<div class="some-outer-class">
<div class="some-class-1">
<input name="x" type="number" ng-model="x">
</div>
<div class="some-class-2">
<input name="y" type="number" ng-model="y">
</div>
<div><i class="some-glyph-icon"></i></div>
</div>
If the decorate attribute is false, or absent, the directive shouldn't do any manipulation.
Couldn't figure out how to do this. Any help is appreciated.
You can simply modify the template in link function :
Demo
link: function(scope, elem, attrs){
if(scope.decorate || attrs.decorate != null){
elem.find('INPUT').wrap('<div class="decorate-class"></div>')
}
}
You can do this inside the directive. You first define a controller inside your directive as follows:
angular.module('some-module').directive('someDirective', function() {
var controller = function($scope) {
//The controller methods
};
return {
restrict: 'E',
replace: 'true',
templateUrl: 'some-template.html',
link: link,
require: '^form',
transclude: true,
scope: {
decorate: '=',
},
controller: controller,
controllerAs: 'myCtrl'
};
});
Inside the controller, you check the decorate value, and make the DOM manipulation accordingly. You can access the decorate value from your controller via the $scope.
var controller = function($scope) {
if($scope.decorate){
//Make the DOM manipulation
}
};
DOM manipulation is done as follows:
var initialInput = document.querySelector('query'); //You have to select your desired input elements here
var decoratedInput = document.createElement("div");
decoratedInput.className += " some-class-1";
decoratedInput.innerHTML = "<input name='x' type='number' ng-model='x'>";
initialInput.parentNode.replaceChild(decoratedInput, initialInput);

Custom AngularJS Directive For Working Hours

I was writing an angularJS directive to input opening hours. Something like:
Here is the directive:
.directive('openhoursDay', function() {
return {
scope: {
openhoursDay:"=",
openhoursActive: "=", //import referenced model to our directives scope
openhoursFrom: "=",
openhoursTo: "="
},
templateUrl: 'templates/open_hours.html',
link: function(scope, elem, attr, ctrl) {
}
}
});
The template:
<div >
<span>{{openhoursDay.day}}</span>
<input type="checkbox" ng-model="openhoursDay.active"/>
<input type="text" ng-model="openhoursDay.open"/>
<input type="text" ng-model="openhoursDay.close"/>
<br>
</div>
HTML:
<div ng-model="work.dt[0]" openhours-day="Sun" openhours-active="active" openhours-from="from" openhours-to="to"></div>
<div ng-model="work.dt[1]" openhours-day="Mon" openhours-active="active" openhours-from="from" openhours-to="to"></div>
<div ng-model="work.dt[2]" openhours-day="Tue" openhours-active="active" openhours-from="from" openhours-to="to"></div>
{{work}}
And Controller:
$scope.work={
dt:[]
};
The problem that I am facing is, scope work is never updated whatever I type on input box, or even if click-unclick checkbox. It remain unchanged as: {"dt":[]}
ng-model is for input fields. So you're passing it in but you weren't really using it for anything. Also you are reading the attributes passed in using = but perhaps you meant to use #. I've created a plunkr demonstrating how you could get this working.
Here's the directive:
.directive('openhoursDay', function() {
return {
scope: {
model:"=",
openhoursDay:"#",
openhoursActive: "#", //import referenced model to our directives scope
openhoursFrom: "#",
openhoursTo: "#"
},
templateUrl: 'open_hours.html',
link: function(scope, elem, attr, ctrl) {
scope.model = {};
scope.model.day = scope.openhoursDay;
scope.model.active = scope.openhoursActive;
scope.model.open = scope.openhoursFrom;
scope.model.close = scope.openhoursTo;
}
}
})
The template:
<div >
<span>{{model.day}}</span>
<input type="checkbox" ng-model="model.active"/>
<input type="text" ng-model="model.open"/>
<input type="text" ng-model="model.close"/>
<br>
</div>
HTML:
<div model="work.dt[0]" openhours-day="Sun" openhours-active="active" openhours-from="from" openhours-to="to"></div>
<div model="work.dt[1]" openhours-day="Mon" openhours-active="active" openhours-from="from" openhours-to="to"></div>
<div model="work.dt[2]" openhours-day="Tue" openhours-active="active" openhours-from="from" openhours-to="to"></div>
work:{{work}}
And Controller:
.controller('MainController', ['$scope', function($scope){
$scope.work={
dt:[]
};
}])
You have to pass the ng-model attribute to the isolated scope, and then, use it in the template as following:
.directive('openhoursDay', function() {
return {
scope: {
openhoursDay: "=",
openhoursActive: "=", //import referenced model to our directives scope
openhoursFrom: "=",
openhoursTo: "=",
ngModel: "=" // Here is the ng-model
},
template: '<div ><span>{{openhoursDay.day}}</span><input type="checkbox" ng-model="ngModel.openhoursDay.active"/><input type="text" ng-model="ngModel.openhoursDay.open"/><input type="text" ng-model="ngModel.openhoursDay.close"/><br> </div>',
link: function(scope, elem, attr, ctrl) {}
};
})
I have created a Plunkr which simulates your situation. You could check it out.

How can i watch for change in a angular directive with $translate

Here's Fiddle Link
How can i watch for change in a directive? In this fiddle example using $translate to translate the content. Everything getting changed except the content in Directive.
HTML looks like this-
<div ng-app='demo'>
<div name="info" ng-controller="myctrl">
<label translate="TERMS_LABEL"></label>
<h4 translate="ZIPCODE_LABEL"></h4>
<p translate="LAST_NAME"></p>
<terms-conditions conditions="TERMS_CONDITIONS" checked="checked"></terms-conditions>
<button type="submit" ng-click="changeLanguage('de')" >Spanish</button>
<button type="submit" ng-click="changeLanguage('en')" >English</button>
</div>
directive looks like
demo.directive("termsConditions",['$translate',function($translate){
return {
restrict:"E",
scope:{
checked:'='
},
link: function(scope, element, attr) {
$translate(attr.conditions)
.then(function (translatedValue) {
scope.conditions = translatedValue;
});
},
template:
"<div class='terms row'><span class='col-md-12'>{{conditions}}</span></div><br><input
type='checkbox' ng-model='checked'><span>Yes, I agree to the terms and condtions</span>"
}
}]);
Is there a reason you can't translate in the template like so?
http://jsfiddle.net/UGLjh/75/
demo.directive("termsConditions",['$translate',function($translate){
return {
restrict:"E",
scope:{
checked:'='
},
link: function(scope, element, attr) {
attr.$observe('conditions', function (untranslatedValue) {
scope.conditions = untranslatedValue;
});
},
template:
"<div class='terms row'><span class='col-md-12'>{{conditions | translate}}</span></div><br><input type='checkbox' ng-model='checked'><span>Yes, I agree to the terms and condtions</span>"
}
}]);
If you know that your attribute won't be interpolated need not use $observe; just stick it on the scope like so:
link: function(scope, element, attr) {
scope.conditions = attr.conditions;
},

Angular directive: How to make assign value to parent scope?

I have a controller AppCtrl as
scope.transaction = {}
The index looks like
<div class="control-group">
<label class="control-label">Date</label>
<div class="controls">
<div class="control-group input-append date form_datetime">
<date-time-picker data-ng-model="transaction.date"></date-time-picker>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label">Amount</label>
<div class="controls">
<div class="input-append">
<input type="text" name="transactionAmount" ng-model="transaction.amount" required>
</div>
and my custom directive looks like
angular.module('customDirectives', []).directive('dateTimePicker', function() {
return {
restrict: 'E',
replace: true,
scope: {
transaction['date']: '=' # COMPILATION ERROR HERE
},
template: '<div class="control-group input-append date form_datetime">'+
'<input type="text" readonly data-date-format="yyyy-mm-dd hh:ii" name="transactionDate" ng-model="transaction.date" data-date-time required>'+
'<span class="add-on"><em class="icon-remove"></em></span>'+
'<span class="add-on"><em class="icon-th"></em></span>'+
'</div>',
link: function(scope, element, attrs, ngModel) {
var input = element.find('input');
element.datetimepicker({
format: "yyyy-mm-ddThh:ii:ssZ",
showMeridian: true,
autoclose: true,
todayBtn: true,
pickerPosition: 'bottom-left'
});
element.bind('blur keyup change', function(){
console.log('binding element');
scope.$apply(date);
});
function date() {
console.log('setting date',input.val());
scope.ngModel = input.val();
}
date(); // initialize
}
}
});
I want to assign the date value from my directive to $scope.transaction.date but it is failing as compilation error, how can I achieve this?
scope: {
transaction['date']: '=' # COMPILATION ERROR HERE
},
Should be
scope: {
transactionDate: '='
},
And
<date-time-picker data-ng-model="transaction.date"></date-time-picker>
Should be
<date-time-picker transaction-date="transaction.date"></date-time-picker>
Then within your directive you can call scope.transactionDate = myValue;
within scope.$apply();
EDIT: If you want to use ng-model within your directive then you can use
....
restrict: 'E',
require: '?ngModel',
....
And
controller.$setViewValue(value); //this will in directive code where you want set the value of the ng-model bound variable.
In Html
<date-time-picker data-ng-model="transaction.date"></date-time-picker>

Resources