angularjs dynamic templateurl values - angularjs

I am trying to create a "name" directive that can host both first and last names.
the code i currently have is:
index.html
<div data-dm-name label="First Name:" info="first_name"></div>
<div data-dm-name label="Last Name:" info="last_name"></div>
directive:
angular
.module('app.names.directive',[])
.directive('dmName', [ directive ])
function directive() {
return {
restrict: 'E',
scope: {
label: '=',
info: '='
},
templateUrl: '/assets/components/name_template.html'
};
}
name_template.html
<div class="wizard-form-group">
<div class="input-group">
<label class="wizard-form-label" for="info">
{{ label }}
</label>
<span class="input-field"
data-ng-class="{
error: form.info.$dirty &&
form.info.$invalid,
focused: form.info.$focused
}"
>
<input
type="text"
name="info"
id="info"
data-ng-model="info"
data-ng-required="true"
data-ng-focus="form.info.$focused = true"
data-ng-blur="form.info.$focused = false"
/>
</span>
</div>
</div>
My problem is that I don't seem to be able to pass in the values for label and info into the template file. What am I doing wrong?
I have just started out using angular so hopefully this has a simple solution.
Thanks in advance

in your directive function add a link function
function directive() {
return {
restrict: 'EA',
scope: {
label: '=',
info: '='
},
templateUrl: '/assets/components/name_template.html',
link : function($scope, element, attrs){
if(attrs.label){
$scope.label = attrs.label
}
if(attrs.info){
$scope.info = attrs.info
}
}
};
}

Your directive is restricted to element, but you're using it as attribute. So you're directive isn't acting upon the element.
You should modify the DDO to:
function directive() {
return {
restrict: 'A', // attribute allowed
scope: {
label: '=',
info: '='
},
templateUrl: '/assets/components/name_template.html'
};
}

Related

Angular Custom Directive .match is not a function

I am trying to create a simple angular radio-group directive. the component will be passed an array of strings, an id, and an attribute to bind the selected option to. When I run my code I get the following error
angular.js:13642TypeError: a.match is not a function
here is what I have:
app.js:
angular.module('atp', [])
.directive('appform', require('./application-directive'))
.directive('radioGroup', require('./radio-group/radio-group-directive'))
.directive('yesNoRadioGroup', require('./radio-group/yes-no-radio-group-directive'));
radio-group-directive.js:
function RadioGroupDirective(){
return{
restrict:'E',
transclude:true,
template:require('./radio-group-template.html'),
replace:true,
scope:{
id:'=',
selected:'=',
options:'='
}
}
}
module.exports = RadioGroupDirective;
radio-group-template.html:
<div>
<label for="{{radioGroupId}}"><ng-transclude></ng-transclude></label>
<fieldset id="{{radioGroupId}}">
<div ng-repeat="option in optionsArray track by $index">
<label for="{{radioGroupId}}-{{$index}}">{{option}}</label>
<input id="{{radioGroupId}}-{{$index}}" type="radio" value="option" ng-model="selectedOption">
</div>
</fieldset>
</div>
yes-no-radio-group-directive.js:
function YesNoRadioGroupDirective() {
return {
restrict: 'E',
transclude:true,
template: require('./radio-group-template.html'),
replace: true,
scope: {
RadioGroupId: '=',
selectedOption: '=',
optionsArray: ['Yes', 'No']
}
}
}
module.exports = YesNoRadioGroupDirective;
usage:
<form>
<yes-no-radio-group radio-group-id="test" selected-option="Controller.Form.SelectedYesNo">Select Yes or No:</yes-no-radio-group>
<radio-group radio-group-id="test-radio" options-array="['Hello World','Some Other Option']" selected="Controller.Form.SelectedYesNo">Select one of the options:</radio-group>
</form>
Why are you doing this? You don't need require at first instance and secondly if you are requiring a html, u need templateUrl instead of template
template:require('./radio-group-template.html'),

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.

AngularJS - Directive ngModel doesn't get updated

I have a good understanding of AngularJS Directives, but I'm thinking I'm missing something here with my directives.
What's wrong : On the initial page load, the ngModel gets triggered correctly and I successfully receive the data and it's modeled in the input.
Everything I do after... doesn't work. If I modify the text in the input, the model is not updated.
Please note that if I don't use a directive (straight HTML), it works fine.
I have a directive like so :
.directive('defaultFormGroup', function () {
return {
restrict: 'A',
templateUrl: 'form-group.html',
replace: true,
scope: {
uniqueId: '#',
labelTitle: '#',
placeholderText: '#',
ngModel: '=',
bsLabelClasses: '#',
bsFormControlClasses: '#'
}
};
})
The directive's template :
<div class="form-group">
<label class="{{bsLabelClasses}} control-label text-left" for="{{uniqueId}}">{{labelTitle}}</label>
<div class="{{bsFormControlClasses}}">
<input type="text" class="form-control" id="{{uniqueId}}" placeholder="{{placeholderText}}" data-ng-model="ngModel">
</div>
</div>
And here's how I call the directive in the template:
<div data-default-form-group
data-label-title="Name"
data-placeholder-text="Name"
data-unique-id="name"
data-bs-label-classes="col-sm-2 col-md-2"
data-bs-form-control-classes="col-sm-3 col-md-3"
data-ng-model="site.name">
</div>
I also have the same issue with radio buttons :
.directive('radioSwitch', function () {
return {
restrict: 'A',
templateUrl: 'radio-switch.html',
replace: true,
scope: {
ngModel: '=',
radioName: '#',
firstId: '#',
firstValue: '#',
firstLabel: '#',
secondId: '#',
secondValue: '#',
secondLabel: '#',
}
};
})
Template:
<input type="radio" name="{{radioName}}" value="{{firstValue}}" id="{{firstId}}" data-ng-model="ngModel">
<label for="{{firstID}}">{{firstLabel}}</label>
<input type="radio" name="{{radioName}}" value="{{secondValue}}" id="{{secondId}}" data-ng-model="ngModel">
<label for="{{secondID}}">{{secondLabel}}</label>
HTML:
<div data-radio-switch
data-ng-model="site.existingCustomer"
data-first-label="Yes"
data-second-label="No"
data-radio-name="existingCustomer"
data-first-value="True"
data-first-id="true"
data-second-value="False"
data-second-id="false">
</div>
What am I missing?
UPDATE
I was missing something in my directive... I want to choose the inputType (text, email, password, etc...)
If it's a textarea, the HTML is different... but it seems this line doesn't work data-ng-if=" inputType !== textarea "> ... if I remove it, it works
Anyone know why?
Here's a plunker : http://plnkr.co/edit/ITElF2epihSALeTutQAz
There doesn't seem to be something wrong with the directive itself: look at the example below with your directive, you can see that model which is the ng-model attribute of the directive gets updated. So, please try to reproduce your problem so we can help you (either embedded snippet, or jsfiddle, or just more code)
angular.module('test', [])
.controller('ctrl', function($scope) {
$scope.model = 'foo';
})
.directive('defaultFormGroup', function () {
return {
restrict: 'A',
template: '<div class="form-group"> <label class="{{bsLabelClasses}} control-label text-left" for="{{uniqueId}}">{{labelTitle}}</label> <div class="{{bsFormControlClasses}}"> <input type="text" class="form-control" id="{{uniqueId}}" placeholder="{{placeholderText}}" data-ng-model="ngModel"> </div> </div>',
replace: true,
scope: {
uniqueId: '#',
labelTitle: '#',
placeholderText: '#',
ngModel: '=',
bsLabelClasses: '#',
bsFormControlClasses: '#'
}
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="ctrl">
<div>model: {{model}}</div>
<div default-form-group ng-model="model"></div>
</div>
Update: it seems that the issue comes from the ng-if, as reproduced in the following snippet. It is fixed by using nh-show instead, as the ng-if may loose the binding from your directive. I am not clear about the exact cause though.
angular.module('test', [])
.controller('ctrl', function($scope) {
$scope.model = 'foo';
})
.directive('defaultFormGroup', function () {
return {
restrict: 'A',
template: '<div ng-if="true"><input type="text" data-ng-model="ngModel" /></div>',
replace: true,
scope: {
ngModel: '='
}
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test" ng-controller="ctrl">
<div>model: {{model}}</div>
<div default-form-group ng-model="model"></div>
</div>

Create custom input directive in angular

I would like to create a custom input that looks like that:
<my-input ng-model="aScopeProperty" placeholder="Enter text"
data-title="This is my title"></my-input>
my-input should receive any property that regular input can get (like placeholder and etc...).
the output should be like this (myInputTemplate.html):
<div class="my-input">
{{title}}
<input type="text" ng-model="text" />
</div>
I created a directive:
myApp.directive('myInput', function(){
return {
restrict: 'E',
require: 'ngModel',
templateUrl: '/myInput/myInputTemplate.html',
replace: true,
scope: {
text: '=ngModel',
title: '=title'
},
}
});
the ng-model is bindded ok now,
my question is:
How can I pass the attributes (like placeholder and etc) from my-input to the inside input?
I think that I approached it the wrong way, maybe I need to do it like that:
<input my-input ng-model="aScopeProperty" placeholder="Enter text"
data-title="This is my title"></input>
and to wrap the input with:
<div class="my-input">
{{title}}
<here will be the original input>
</div>
directive call should be like
<my-input ng-model="aScopeProperty" placeholder="'Enter text'" title="'This is my title'"></my-input>
note the placeholder="'Enter text'" Enter text with in quotes ('), this indicate these values are string so angular will not search for scope variable.
and in the directive
myApp.directive('myInput', function(){
return {
restrict: 'E',
require: 'ngModel',
templateUrl: '/myInput/myInputTemplate.html',
replace: true,
scope: {
text: '=ngModel',
title: '=title',
placeholder : '=placeholder'
},
}
});
and the template
<div class="my-input">
{{title}}
<input type="text" ng-model="text" placeholder="{{ placeholder }}" />
</div>
here is the demo Plunker
You can use ng-attr as the following:
<input type="text" ng-model="text" ng-attr-placeholder="{{placeholder}}"/>
And send placeholder as attribute in your scope as the following:
scope: {
text: '=ngModel',
title: '=title',
placeholder : '=placeholder'
}
I recommend to read about ng-attr-attrName, and this useful answer.
Dynamic attributes
Read my question, and accepted answer.
The second approach succeeded!
final code:
<input my-input ng-model="aScopeProperty" placeholder="Enter text"
data-title="This is my title">
The Directive:
app.directive('myInput', function () {
return {
restrict: 'A',
scope: {
title: '=title'
},
link: function ($scope, $element) {
var wrap = angular.element('<div class="my-input-wrapper" />');
$element.addClass('form-control').removeAttr('my-input');
wrap.insertBefore($element);
$element.appendTo(wrap);
if ($scope.title) {
var title = angular.element('<span class="my-title">' + $scope.title + '</span>');
title.appendTo(wrap);
}
},
}
});
I even created my first Plunker for it, unfortunately, the Plunker don't works because it doesn't recognize: insertBefore and appendTo
http://plnkr.co/edit/XnFM75vOBg4ifHUQzGOt?p=preview

Resources