Angular Js : access data in directive and create form control - javascript

I have a array with form questions which has label(_text), type(QuestionData._fieldType). on basis of fieldtype I want to creata directive.
Here I am stuck how to pass parameters to directives and use inside directive.
html
<div ng-controller="autoQuoteCtrl">
<form class="form-horizontal text-center" role="form" name="DTOstep1" ng-submit="onSubmit()">
current page:{{$state.current.name}}
<div ng-repeat="que in questions[$state.current.name]">
<div ng-if="que.QuestionData._fieldType === 'text'" >
text - <code>{{que.QuestionData._attributeName}}</code>
<text-control-dir data="que"></text-control-dir>
<!-- <question-dir>print from directive</question-dir> -->
</div>
<div ng-if="que.QuestionData._fieldType === 'select'" >
select - <code>{{que.QuestionData._attributeName}}</code>
<select-control-dir data="que"></select-control-dir>
</div>
<div ng-if="que.QuestionData._fieldType === 'radio'" >
select - <code>{{que.QuestionData._attributeName}}</code>
<radio-control-dir data="que"></radio-control-dir>
<!-- <question-dir>print from directive</question-dir> -->
</div>
<div ng-if="que.QuestionData._fieldType === 'hidden' && que.QuestionData._attributeName != 'CBQ'" >
hidden - <code>{{que.QuestionData._attributeName}}</code>
<hidden-control-dir data="que"></hidden-control-dir>
<!-- <question-dir>print from directive</question-dir> -->
</div>
</div>
<input type='hidden' id="save_quote_email" name="save_quote_email" ng-model="AutoQuote.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails[0].EmailAddress" value="praveend06#gmail.com" />
{{AutoQuote.postAutoQuoteObj.ApplicationInfo.GeneralPartyInfo.ContactInfo.Emails[0].EmailAddress}}
<input type="submit" value="Save" />
{{AutoQuote.postAutoQuoteObj.SessionInfo.StateCode}}
</form>
</div>
controlDirective.js
(function () {
"use strict";
angular
.module("autoQuote")
.directive('textControlDir', [textControlDir])
.directive('selectControlDir', [selectControlDir])
.directive('radioControlDir', [radioControlDir])
.directive('hiddenControlDir', [hiddenControlDir]);
function textControlDir(data)
{
console.log('here in text directive');
console.log(data);
return {
transclude: true, // append html
restrict: 'E',
template: "<div ng-transclude></div>\n\
\n\
<label>{{data._text}} </label><input type='text' name='' id='' value='' >"
};
}
function selectControlDir()
{
console.log('here in select directive');
return {
transclude: true,
template: "<h1>Made by a select directive!</h1>"
};
}
function radioControlDir()
{
console.log('here in radio directive');
return {
transclude: true,
template: "<h1>Made by a radio directive!</h1>"
};
}
function hiddenControlDir()
{
console.log('here in hidden directive');
return {
transclude: true,
template: "<h1>Made by a hidden directive!</h1>"
};
}
}());
please check my plunker link for complete code. http://plnkr.co/edit/Op1QDwUBECAosPUC7r3N?p=preview

when you want to define the template of your directive, instead of template itself you can use a function of the form:
angular.module("autoQuote")
.directive('question', function() {
return {
template: function(elem, attrs) {
if (angular.isDefined(attrs["type"])) {
switch attrs["type"]:
case "text":
return "<input type='text' name='' id='' value='' >"
case "radio":
// return radio template
}
}
....
}
});
and you can write a general directive like question and use it like this: <question type="{{que.QuestionData._fieldType}}"></question>.
Also you can check this answer for more information.
Hope it helps

Related

Do AsyncValidators fire all the time?

I am using angular.js 1.6.4 version. I created a directive for server-side validation and I see that it's firing when I am loading the form, which is wrong. I only want to fire my code when I changed the value. My HTML code is
<div class="col-xs-6">
<div class="controls">
<label class="control-label"
ng-hide="editRetailTrackingForm.barcode.$dirty && editRetailTrackingForm.barcode.$error">
#Labels.barcode:
</label>
<input type="text" name="barcode"
ng-model="currentItem.barcode"
sm-code-unique-validator
table-name="items"
column-to-test="barcode"
error-message="itemBarcodeErrorMessage"
primary-key="currentItem.itemId"
ng-model-options="{ updateOn: 'blur', debounce: { default : 500, blur: 0 }}"
class="form-control"
ng-maxlength="100" />
<div ng-class="{loading:editRetailTrackingForm.barcode.$pending}">#String.Format(Messages.validatingX, Labels.barcode)</div>
<div ng-if="editRetailTrackingForm.barcode.$dirty">
<div ng-messages="editRetailTrackingForm.barcode.$error">
<div ng-message="maxlength">
<label class="field-validation-error control-label-error animate-show">
#String.Format(Messages.cannotExceed, Labels.barcode, "100")
</label>
</div>
<div ng-message="smCodeUnique">
<div class="info-text-block-error">
{{itemBarcodeErrorMessage}}
</div>
</div>
</div>
</div>
</div>
</div>
and my directive code is very similar to http://www.codelord.net/2014/11/02/angularjs-1-dot-3-taste-async-validators/
return {
require: "ngModel",
scope: {
primaryKey: "=?",
tableName: "#",
columnToTest: "#",
errorMessage: "=?"
},
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.smCodeUnique = function (modelValue, viewValue) {
if (!viewValue) {
return true;
}
let codeObject = {
id: $scope.primaryKey, tableName: $scope.tableName,
columnToTest: $scope.columnToTest, code: viewValue
};
return services.Http.put('api/items/checkCodeUniqueness', codeObject).then(
function (response) {
if (!response.data.isValid) {
$scope.errorMessage = response.data.errorMessage;
return services.Deferred.reject(response.data.errorMessage);
}
return true;
}
);
};
}
};
When I am debugging my code I see that server side code is running multiple times when I only instantiate my form (and not even open the correct tab where this field is).
So, how should I change my directive or ng-options to only fire validations when I changed my value?

Setting ngIf dynamically on a form required field with a custom directive

First of all I'm kinda new to Angular. I've created a directive that is being used in my form-group div in the HTML. This contains a required input. The ideia of this directive is to check if the entire div will be shown based on a scope value.
Visually, this works as expected but... when setting the ng-if directive to a false value, the form submission still gives an error as a required value is missing when the form doesn't even contain that input anymore.
This is my code:
// My Directive
app.directive("showCountry", function ($compile) {
var linkFunction = function (scope, element, attributes) {
var testingVariable = scope.testingVariable;
if (testingVariable) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
attributes.$set("ngIf", false);
compile(element)(scope);
break;
}
}
};
return {
restrict: "A",
link: linkFunction
};
});
<!-- My HTML with required field using my directive -->
<div class="form-group" show-country>
<label class="col-lg-6 col-md-6 control-label">
Country
</label>
<div class="col-lg-6 col-md-6">
<input name="country" type="text" placeholder="Country" ng-model="country" ng-required="true"/>
</div>
</div>
Thank you guys.
Take a scope variable validateand make it false in the condition,
if (testingVariable.toLowerCase()) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
scope.validate = false;
attributes.$set("ngIf", false);
$compile(element)(scope);
break;
}
}
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp" ng-controller="test">
<form name="myForm">
The country input is hided and animation wil not occur
<div class="form-group" show-country validate="validate">
<label class="col-lg-6 col-md-6 control-label">
Country
</label>
<div class="col-lg-6 col-md-6">
<input name="country" type="text" placeholder="Country" ng-model="country" ng-required="true" ng-if="validate"/>
</div>
</div>
</form>
<h1>{{myForm.country.$error}}
<script>
var app = angular.module("myApp", []);
app.directive("showCountry", function ($compile) {
var linkFunction = function (scope, element, attributes) {
var testingVariable = scope.testingVariable;
console.log(testingVariable.toLowerCase())
if (testingVariable.toLowerCase()) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
scope.validate = false;
attributes.$set("ngIf", false);
$compile(element)(scope);
break;
}
}
};
return {
restrict: "A",
link: linkFunction
};
});
app.controller("test", function ($scope) {
$scope.testingVariable = 'false';
});
</script>
</body>
</html>
Here is the DEMO with validation Occuring, Your scenario
DEMO with novalidation, Required answer

Bind inner directive to its parent form

Having a directive, my-drtv , with <input ng-required="true"> within <div ng-form="myForm"> .
Currently the inner ng-required isn't bind to its form (myForm) , how could I set to my-drtv the same form as its parent ?
(so that in the initial state myForm.$valid should be false)
JS:
var myAppModule = angular.module('myAppModule', []).
directive('myDrtv',function(){
return {
restrict: 'A',
template: '<div><input ng-required="true"></div>'
}
});
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<html ng-app="myAppModule">
<body>
<div ng-form="myForm">
<div my-drtv>
</div>
<br>
{{myForm.$valid}}
</div>
</body>
</html>
In order to have validation behaviour input fields must have both ngModel and name attributes. Then it will be registered as control under form controller. So you could do
.directive('myDrtv', function() {
return {
restrict: 'A',
template: '<div><input name="inp" ng-model="inp" ng-required="true"></div>'
}
});
or better pass model and name from outside, then directive will become much more reusable:
.directive('myDrtv', function() {
return {
restrict: 'A',
scope: {
model: '=ngModel'
},
template: function(element, attrs) {
return '<div><input name="' + attrs.name + '" ng-model="model" ng-required="true"></div>';
}
}
});
and use it like this:
<div ng-form="myForm">
<div my-drtv name="some" ng-model="someField"></div>
</div>
Demo: http://plnkr.co/edit/FV7jeiuLvqPmIlVyyXWr?p=preview

Cannot get the variable in ng-model in directive template

I have a directive for comment input as follows, I want to reset the form after the user posted the comment. However, I can not get the newComment value of ng-model in link function. How to solve such problem.
commenting.html
<div class="directive__commenting">
<div class="col-content">
<h4>{{title}}({{count}})</h4>
<form class="form" name="commentForm" ng-submit="createComment(commentForm, newComment)" ng-if="isLoggedIn()">
<div class="form-group">
<textarea class="form-control" name="newComment" rows="3" placeholder="你怎么看?" ng-model="newComment" required></textarea>
</div>
<div class="right">
<span id="count-words" ng-class="{'red': isWordsExceeded(newComment)}">{{140 - newComment.length}}</span>
<button class="send-button btn btn-default" type="submit" ng-disabled="isWordsExceeded()">{{btnActionTitle}}</button>
</div>
</form>
</div>
</div> <!-- #create-comment -->
commenting.directive.js
'use strict';
angular.module('myapp')
.directive('commenting', function (Auth) {
return {
templateUrl: 'components/directive/commenting/commenting.html',
restrict: 'EA',
scope: {
title: '=',
count: '=',
btnActionTitle: '=',
action: '='
},
link: function (scope) { //, element, attrs
scope.isLoggedIn = Auth.isLoggedIn;
scope.isWordsExceeded = function (newComment) {
return newComment && newComment.length > 140;
}; //- isWordsExceeded
scope.createComment = function (form, newComment) {
scope.action(form, newComment)
.then(function () { //success
// clear the form, however here scope.newComment is undefined
})
.catch(function () { //fail
});
};
}
};
});
The directive is added in a html file as follows.
<div class="row" id="create-comment">
<commenting title="'Comments'" count="model.comments.length" btn-action-title="'Submit comment'" action="createComment"></commenting>
</div> <!-- #create-comment -->
Try to access through scope like
scope.newComment

directive not generating html

I am having a problem with my code basically i have this span (dynamically created via ng-repeat)
<span my-size id="abc"></span>
<span my-size id="def"></span>
<span my-size id="ghi"></span>
what I need to achieve is to get the id of each span and split its character and created checkbox and used the split[] i get when i split the id to be its value
<span id="abc">
<input type="checkbox" value="a">
<input type="checkbox" value="b">
<input type="checkbox" value="c">
</span>
<span id="def">
<input type="checkbox" value="d">
<input type="checkbox" value="e">
<input type="checkbox" value="f">
</span>
<span id="ghi">
<input type="checkbox" value="g">
<input type="checkbox" value="h">
<input type="checkbox" value="i">
</span>
could anyone help me do this in angular js directives
this is all i have so far :
myApp.directive('mySize', function () {
return {
restrict: 'E',
scope: { html: '#' },
template: '<span ng-bind-html="html"></span>',
link : function (scope, element, attrs) {
scope.html="<h1>sample html </h1>";
}
}
});
I can't go further since my directives wont generate html tags
I'm not sure what your initial intention was when writing the directive, because there is really no need to either use a link-function or ng-bind-html.
For what you've asked the directive could be as simple as:
(function (app, ng) {
'use strict';
app.directive('mySize', function () {
return {
restrict: 'A',
scope: { id: '#id' },
template: '<input type="checkbox" data-ng-repeat="char in id track by $index" value="{{ char }}">'
}
});
}(angular.module('app', []), angular));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
<div data-ng-app="app">
<span data-my-size id="abc"></span>
<span data-my-size id="def"></span>
<span data-my-size id="ghi"></span>
</div>
Edit
If you you want to add extra information just fiddle with the template. E.g.:
(function (app, ng) {
'use strict';
app.directive('mySize', function () {
return {
// actually obsolute, because it's the default setting
restrict: 'A',
// reusing the directive name to simplify the required view-html,
// but mapping it to a more fitting name when used internally
scope: { str: '#mySize' },
// the actual template (this time using a label)
template: '<label data-ng-repeat="char in str track by $index"><input type="checkbox" value="{{ char }}"> {{ char }}</label>'
}
});
}(angular.module('app', []), angular));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
<div data-ng-app="app">
<div data-my-size="abc"></div>
<div data-my-size="def"></div>
<div data-my-size="ghi"></div>
</div>
It doesn't work because you restricted it's usage to element and use it as attribute. Change restrict: 'E' to restrict: 'A'.
var app = angular.module('app', []);
app.directive('mySize', function($sce) {
return {
restrict: 'EA',
scope: {
id: '#'
},
template: '<label ng-repeat="i in array"><input type="checkbox" ng-value="i" >{{i}}<label>',
link: function(scope, element, attrs) {
scope.array = scope.id.split("")
}
}
});
app.controller('homeCtrl', function($scope) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="homeCtrl">
<span my-size id="abc"></span>
<span my-size id="def"></span>
<span my-size id="ghi"></span>
</div>
</div>
The directive can look like this:
.directive('mySize', function() {
return {
restrict: 'AE',
link: function(scope, element, attrs) {
element[0].id.split('').map(function(el) {
element.append('<label><input type="checkbox" value="' + el + '"> ' + el + '</label>');
});
}
}
});
Demo: http://plnkr.co/edit/nZMEdUjMXG3MDYv19H5C?p=preview

Categories