AngularJS custom directives - angularjs

I'm creating template for text inputing using angular directives.
Directive will receive 3 attributes: title, placeholder and model.
I need attribte model to be implemented into atribute ng-model in directive template.
For example:
if i create element with next attributes
<ng-text-input model="test" title="First name" placeholder="First name"></ng-text-input>
result will be next:
<div class="form-group">
<label class="col-sm-2 control-label">First name</label>
<div class="col-sm-9">
<input ng-model="test" type="text" class="form-control" placeholder="First name">
</div>
</div>
And how can i use model "test" in parent scope?
Thanks
upadete after #Maxdow comment:
directive declaration:
app.directive('ngTextInput', function(){
return {
restrict : 'AE',
scope: {
title: '#',
placeholder : '#',
myModel: '=ngModel'
},
templateUrl : 'ng-textInput.html'
}
});
template:
<script type="text/ng-template" id="ng-textInput.html">
<div class="form-group">
<label class="col-sm-2 control-label">{{title}}</label>
<div class="col-sm-9">
<input ng-model="myModel" type="text" class="form-control" placeholder={{placeholder}}>
</div>
</div>
</script>
using:
<ng-text-input ng-model="test" title="First name" placeholder="First name"></ng-text-input>
but result is still:
<div class="form-group">
<label class="col-sm-2 control-label ng-binding">First name</label>
<div class="col-sm-9">
<input ng-model="myModel" type="text" class="form-control ng-pristine ng-valid" placeholder="First name">
</div>
</div>
What am i doing wrong?

In your directive bind your attribute with ngModel :
app.directive('myDirective', function() {
return {
restrict: 'AE',
scope: {
myModel: '=ngModel'
},
template:'<input ng-model="myModel"/>'
}});
You should be able to use is from your HTML like this :
<my-directive ng-model="whatyouwant"></my-directive>
An example : http://jsfiddle.net/maxdow/6GU6x/

Related

Programmatically apply classes to angularjs form

I have an angular directive to facilitate the adding of bootstrap classes at runtime to streamline the need to apply "form-group", "control-label" and "form-control". This works perfectly as long as I don't try to include multiple levels at once, meaning that I cannot seem to make this work to include multiple divs in "form-group. I have attached the code, raw HTML and processed HTML for review to see if someone might have some insight into how I might modify to make this tool meaningful.
Directive:
(function () {
"use strict";
angular.module("ppac")
.directive("formfix", formfix);
var addClasses = function (element) {
var input = element.querySelector("input, textarea, select");
var type = input.getAttribute("type");
if (type !== "checkbox" && type !== "radio") {
input.classList.add("form-control");
}
var label = element.querySelector("label");
label.classList.add("control-label");
element.classList.add("form-group");
};
function formfix() {
return {
restrict: "A",
link: function (scope, element) {
addClasses(element[0]);
}
}
}
})();
HTML Form:
<form name="contactForm" ng-submit="model.submit()" novalidate>
<div class="form-horizontal">
<div formfix>
<label for="firstName" class="col-md-2">First Name</label>
<div class="col-md-3">
<input type="text" name="firstName" id="firstName" ng-model="model.contact.firstName" />
</div>
<label for="lastName" class="col-md-2">Last Name</label>
<div class="col-md-3">
<input type="text" name="lastName" id="lastName" ng-model="model.contact.lastName" />
</div>
</div>
</div>
</form>
Processed HTML:
<form name="contactForm" ng-submit="model.submit()" novalidate="" class="ng-pristine ng-valid">
<div class="form-horizontal">
<div formfix="" class="form-group">
<label for="firstName" class="col-md-2 control-label">First Name</label>
<div class="col-md-3">
<input type="text" name="firstName" id="firstName" ng-model="model.contact.firstName" class="ng-pristine ng-valid form-control ng-empty ng-touched">
</div>
<label for="lastName" class="col-md-2">Last Name</label>
<div class="col-md-3">
<input type="text" name="lastName" id="lastName" ng-model="model.contact.lastName" class="ng-pristine ng-untouched ng-valid ng-empty">
</div>
</div>
</div>
</form>
You can use ng-class to add class dynamically as the document says
The ngClass directive allows you to dynamically set CSS classes on an
HTML element by databinding an expression that represents all classes
to be added.
Reference
https://docs.angularjs.org/api/ng/directive/ngClass

AngularJS How to manipulate array of objects if each element is stored inside a stand alone directive?

I've created a custom directive to serve as a template to show some information using ng-repeat. I also need to do some manipulation on the array that being looped. My question is how can I remove or add elements to that array, if each element is inside a separate scope inside a stand-alone directive? Without the use of the directive the task is easy:
<div class="well" ng-repeat="dat in data">
<form novalidate>
<div class="form-group">
<label for="name">name:</label>
<input type="text" class="form-control" id="name" ng-model="dat.name" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="balance">balance:</label>
<input type="text" class="form-control" id="balance" ng-model="dat.balance" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="fruit">favorite Fruit:</label>
<input type="text" class="form-control" id="fruit" ng-model="dat.favoriteFruit" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="greeting">greeting:</label>
<input type="text" class="form-control" id="greeting" ng-model="dat.greeting" ng-disabled="enableEdit">
</div>
<button class="btn btn-danger" ng-click="remove($index)">remove</button>
<button class="btn btn-default" ng-click="enableEdit=!enableEdit">edit</button>
<button class="btn btn-success" ng-click="save(dat,$index);enableEdit=!enableEdit" ng-disabled="enableEdit">save</button>
</form>
</div>
After the refactoring to directive, the task is not so obvious:
<div class="well" ng-repeat="dat in data">
<data-directive user="dat" index="{{$index}}" arr="data"></data-directive>
</div>
The directive template looks as follows:
<form novalidate>
<div class="form-group">
<label for="name">name:</label>
<input type="text" class="form-control" id="name" ng-model="user.name" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="balance">balance:</label>
<input type="text" class="form-control" id="balance" ng-model="user.balance" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="fruit">favorite Fruit:</label>
<input type="text" class="form-control" id="fruit" ng-model="user.favoriteFruit" ng-disabled="enableEdit">
</div>
<div class="form-group">
<label for="greeting">greeting:</label>
<input type="text" class="form-control" id="greeting" ng-model="user.greeting" ng-disabled="enableEdit">
</div>
<button class="btn btn-danger" ng-click="remove(index)">remove</button>
<button class="btn btn-default" ng-click="enableEdit=!enableEdit">edit</button>
<button class="btn btn-success" ng-click="save(user,$index);enableEdit=!enableEdit" ng-disabled="enableEdit">save</button>
</form>
Directive js:
app.directive("data-directive", ["dataService", function (dataService) {
return {
restrict: 'E',
templateUrl:"directives/dataDirectiveTemplate.html",
scope:{
user: "=",
index: "#",
arr: "="
},
controller: function ($scope) {
$scope.enableEdit = true;
$scope.remove = function (index) {
console.log(arr);
dataService.removeItem(arr, parseInt(index));
};
$scope.save = function (item,index) {
dataService.saveItem(item, index, $scope.data);
};
$scope.changes = function () {
console.log($scope.data);
};
}
}
}]);
I managed to pass the $index variable, but how do I pass the whole data array of objects?
Let's first define an owner for data. It can be the controller whose view is using data-directive or dataService.
Now, owner holds data and all responsibility to manipulate it.
If it is dataService, its method can be called from the directive and data is already available with it.
If it is controller it can pass method using & e.g.:
scope: {
user: "=",
index: "#",
arr: "=",
onRemove: "&",
onSave: "&",
onChange: "&",
},

Wrap exist directive in angular

I am using angular js in my application, and I have a form which contains a lot of fields:
<form>
<div class="form-group">
<label for="idname">Name:</label>
<input type="name" class="form-control" id="idname" ng-model="name" name="name">
</div>
<div class="form-group">
<label for="idemail">Email Address:</label>
<input type="password" class="form-control" id="idemail" ng-model="email" name="email">
</div>
<div class="form-group">
<label for="idtype">Choose Type:</label>
<select class="form-control" id="idtype" name="type">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
There are almost 60+ fileds, and most of the markups is bootstrap styles related, so I want to simplify the markups, like this:
<form>
<input label="Name:" type="text" model="name">
<input label="Email Address:" type="email" model="email">
<select label="Choose Type:" model="type">
....
</select>
<button type="submit" class="btn btn-default">Submit</button>
</form>
I want to add some extra attributes like label and model for the form inputs, then I will generate the label and input element and wrap them with the bootstrap styles. Also I want the third directives like min-length or anything else still take effect.
I tried to create the directive like this:
.directive('label', function() {
return {
priority:1,
restrict: 'A',
templateUrl: "field.html",
replace:true
};
})
However it does not work as expected, the custom-ed element like
<input label="Name:" type="text" model="name">
are not inserted into the template, and the label is not generated:
<div class="form-group">
</div>
I think the compile and link may be necessary, but I have no idea how to implement them.
This is the demo.
Is it possible to fix it?
Replace is deprecated since Angular 1.3.
But it works: https://jsfiddle.net/basslagter/yh0qdbhL/1/
What you can do (because of the deprecation) is make a custom element:
<custom-label label="Name:" type="text" model="name"></custom-label>
Defined as:
var myApp = angular.module('myApp', []);
myApp.directive("customLabel", function () {
return {
restrict: "E",
template: '<label>The label was: {{vm.label}}</label>',
controllerAs: 'vm',
scope: { label: '#' },
bindToController: true,
controller: function(){}
};
});
See: https://jsfiddle.net/basslagter/yh0qdbhL/

Bootstrap form validation with Angular directive

I am able to get the form-control class from Bootstrap to behave well within a single HTML file. But when the form-control is defined from within a directive, the flags like $dirty are not being recognized. The class ng-dirty does appear.
HTML using directive:
<form class="form-horizontal" role="form" name="formExpense">
<div frm-item ng-repeat="f in formdata2"></div>
</form>
Directive:
app.directive('frmItem', function() {
return {
restrict: 'A',
templateUrl: 'form.html'
};
});
Template:
<div class="form-group" ng-class="{'has-error':formExpense.{{f.name}}.$dirty}">
<div class="col-md-6 text-right">
<label for="{{f.name}}-entry">{{f.name}}</label>
</div>
<div class="col-md-6">
<input type="text" name="{{f.name}}" ng-model="f.amount"
class="form-control" placeholder="per month">
</div>
</div>
$scope:
$scope.formdata2 = [{'name': 'housing'},{'name': 'medical'}];
Plunk: http://plnkr.co/JcanBWWTphGdL18v6NxZ

Pass ng-model and place-holder value into directive

I have a segment of code needs to be reuse a lot, there for I want to just create a directive for it.
<div class="btn-group">
<div class="input-group">
<div class="has-feedback">
<input type="text" class="form-control" placeholder="BLAH BLAH" ng-model="model">
<span class="times form-control-feedback" ng-click="model=''" ng-show="model.length > 0"></span>
</div>
</div>
</div>
I want to use this code as template in directive.
Create a directive used as follow:
<div search-Field ng-model="model" placeholder="STRING"></div>
to replace to old html, ng-model and placeholder will be as variables.
angular.module('searchField', [])
.directive('searchField', [function () {
return {
scope: {
placeholder: '#',
ngModel: '='
},
templateUrl: 'Partials/_SearchInputGroup.html'
}
}]);
Is it the way of doing it?
That looks fine.
Here is a sample for you -http://plnkr.co/edit/LCWHRj6xc9bxwrgpaAb4
corrected few typos and binded placeholder and ngModel data in the directive.
Template:
<div class="btn-group">
<div class="input-group">
<div class="has-feedback">
<input type="text" class="form-control" placeholder="{{placeholder}}" ng-model="ngModel">
<span class="times form-control-feedback" ng-click="model=''" ng-show="ngModel.length > 0">Show</span>
</div>
</div>
</div>

Resources