Angular Custom Directive .match is not a function - angularjs

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'),

Related

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);

angularjs dynamic templateurl values

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'
};
}

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>

Bootstrap switch not working for nested directives inside ng-repeat

Please read the code below:
<div ng-repeat="item in data.items">
<list-item></list-item>
</div>
Html(list_item.html) of the above directive(listItem) is as below(have shown only a small part of html):
<div class="active-icon-list">
<switch-check status="{{ item.status }}"></switch-check>
</div>
js of the above directive is as below:
directives.directive('cusListItem', function(){
return {
replace: true,
restrict: 'E',
templateUrl: "list_item.html",
link: function($scope, iElm, iAttrs, controller) {
// -----
}
};
});
Html(switch_check.html) of the above directive(switchCheck) is as below:
<div class="make-switch switch-small switch-mini active-list-switch">
<input type="checkbox" checked ng-if="status == 'active'">
<input type="checkbox" ng-if="status == 'inactive'">
</div>
js of the above directive is as below:
directives.directive('switchCheck', function($timeout) {
var switches = [];
return {
replace: true,
restrict: 'E',
scope: { status: '#'},
templateUrl: "switch_check.html",
link: function postLink($scope, iElm, iAttrs) {
iElm['bootstrapSwitch']();
}
}
});
I have made directives for the purpose of reusability.
Since I am using bootstrapSwitch.js instead of normal checkbox, I have created a directive.
If a remove ng-if and write a traditional input tag, this works properly.
<input type="checkbox" checked>
But if I use ng-if, iElm['bootstrapSwitch'](); fails and checkbox does not appear at all.
Is there a way(an efficient one) to figure out a solution for this one?
Please tell me if my question is not clear.

Angularjs: validation not working when control is based on directive

Being rather new to Angularjs, I am creating textbox-label combinations in Angularjs using directives. It's working very well, but I can't get validation to work. Here is a stripped-down example.
The Html:
<form name="form" novalidate ng-app="myapp">
<input type="text" name="myfield" ng-model="myfield" required />{{myfield}}
<span ng-show="form.myfield.$error.required">ERROR MSG WORKING</span>
<br>
<div mydirective FIELD="myfield2" />
</form>
The Javascript:
var myapp = angular.module('myapp', []);
myapp.directive('mydirective', function () {
return {
restrict: 'A',
scope: { ngModel: '=' },
template: '<input type="text" name="FIELD" ng-model="FIELD" />{{FIELD}}
<span ng-show="form.FIELD.$error.required">ERROR MSG NOT WORKING</span>'
};
});
The hard coded input - myfield - works, the other - myfield2 - doesn't (the binding does, just not the required-error message).
How do I tell the ng-show attribute to sort of "replace" FIELD in form.FIELD.$error.required by myfield2?
Here is a jsFiddle.
The problem is that your directive creates a new scope for the directive, this new scope does not have access to the form object in the parent scope.
I came up with two solutions, though I suspect there is a more elegant "Angular" way to do this:
Passing down the form object
Your view becomes:
<div mydirective FIELD="myfield2" form="form" />
And the scope definition object:
return {
restrict: 'A',
scope: {
ngModel: '=',
form: '='
},
template: '<input type="text" name="FIELD" ng-model="FIELD" required/>{{FIELD}}<span ng-show="form.FIELD.$error.required">ERROR MSG NOT WORKING</span>'
};
I've updated the fiddle with this code: http://jsfiddle.net/pTapw/4/
Using a controller
return {
restrict: 'A',
controller: function($scope){
$scope.form = $scope.$parent.form;
},
scope: {
ngModel: '='
},
template: '<input type="text" name="FIELD" ng-model="FIELD" required/>{{FIELD}}<span ng-show="form.FIELD.$error.required">ERROR MSG NOT WORKING</span>'
};

Resources