Bind inner directive to its parent form - javascript

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

Related

$parse.assign(..) is not a function Angular JS version 1.4.3

I am facing this problem while selecting file and showing its name on span.
So basically I am trying that whenever I select some file I want to change the span Tag. This is my view
<form name="fileUploadForm" ng-submit="submitFile(fileUploadForm.$valid)">
<div class="form-group upload-btn-wrapper">
<input type="file" class="form-control" id ="myFileField" file-input="patient_file" required />
<button class="csv-upload-btn">choose file</button>
<span id="file-chosen">{{ patient_file }}</span>
</div>
<div class="form-group">
<input type="submit" value="Upload" class="btn btn-primary">
</div>
</form>
following is my directive code
(function() {
angular.module('practimyze.dashboard')
.directive('csvUploader', ["$parse", function($parse) {
return {
restrict: 'EA',
templateUrl: "dashboard/breakdown/csv-uploader/csv-uploader.tpl.html",
replace: true,
controller: function($scope, valueHandler, Auth, $rootScope, blockUi, DashboardApi, fileUploadService, apiLinks, toaster){
},
link: function(scope, element, attrs) {
var model = $parse(attrs.csvUploader);
var modelSetter = model.assign;
element.bind('change', function() {
scope.$apply(function() {
modelSetter(scope, element[0].patient_file);
});
});
}
};
}]);
})();
Initially I did this
$parse.assign(scop, element[0].files);
this was getting me error that parse has not function assign. Then I changed it to what i have written now it says (modelSetter is not a function).
I am not sure where i am doing wrong, Please help me out thanks
Edited:
this is the fiddle link, it seems to be working perfect there fiddle link

Angular Js : access data in directive and create form control

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

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

How to select dynamically generated elements from inside an AngularJS directive?

In my directive, I need to select out certain DOM elements, some of which are generated dynamically in an ng-repeat loop. If I do it in a straightforward way, I will only get the static elements. However, if I delay the selection by, say, 500ms, I will get all elements, which is what I want.
Although this works, it is not an ideal solution, and certainly doesn't seem like best practise. On the one hand, you'd like to keep the timeout as short as possible, but on the other hand, you want to be sure that the DOM is ready before selecting.
Is there an event which fires when all dynamic DOM is ready? What is the recommended way to select dynamically generated elements from an AngularJS directive?
EXAMPLE:
HTML:
<div data-my-directive>
<div class="modal-body">
<label data-localize>type:</label>
<select class="form-control" ng-model="assetFilter.appCode" ng-change="loadassets(assetFilter.appCode)" ng-options="type.code as type.name for type in types"></select>
<table class="table table-default" ng-show="hasLoaded">
<tbody ng-repeat="asset in assets | filter:assetFilter | orderBy:'assetKey':false">
<tr>
<td>
<div class="container-fluid">
<div class="row vert-align">
<div class="col-sm-4">
{{asset.assetKey}}
</div>
<div class="col-sm-8" style="height:100%">
<input ng-hide="asset.assetKey.length >= 80" type="text" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true">
<textarea ng-show="asset.assetKey.length > 80" class="form-control" ng-model="asset.assetValue" ng-change="asset.isModified=true"></textarea>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="save(saveassets, $event)" ng-disabled="!(assets | anyModified)" data-localize>Save</button>
<button class="btn btn-warning" ng-click="close($event)" data-localize>Close</button>
</div>
</div>
Directive:
myApp.directive('myDirective', function ($timeout) {
return {
restrict: 'A', //attribute only
link: function (scope, elem, attr, ctrl) {
var context = elem[0];
var availableFormElements = 'input:not([disabled]):not([class*=ng-hide]),' +
'select:not([disabled]):not([class*=ng-hide]), textarea:not([disabled]):not([class*=ng-hide]),' +
'button:not([disabled]):not([class*=ng-hide]),' +
'*[class*=btn]:not([disabled]):not([class*=ng-hide])';
var allFormElements = context.querySelectorAll(availableFormElements);
// Will only get static elements, nothing from ng-repeat loop
$timeout(function () {
allFormElements = context.querySelectorAll(availableFormElements);
// Will include all elements, also from ng-repeat loop
}, 500);
// Code to manipulate selected form elements
};
});
This is a simple example how you could work it out.
Imo the only drawback to this solution is you can't use an isolate scope.
html
<div data-ng-controller="MainController">
<div outer-directive>
<ul>
<li ng-repeat="asset in assets" inner-directive>
{{asset}}
<input type="text" class="form-control">
</li>
</ul>
</div>
</div>
js
var app = angular.module('myApp', []);
app.controller('MainController',function($scope) {
$scope.assets = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
});
app.directive('outerDirective', function() {
return {
restrict: 'A',
controller: function($scope) {
}
};
});
app.directive('innerDirective', function() {
return {
restrict: 'A',
require: '^outerDirective',
link: function(scope, elem, attrs,ctrl) {
var context = elem[0];
if (scope.$last){
var availableFormElements = 'input,textarea';
var allFormElements = context.querySelectorAll(availableFormElements);
console.log(allFormElements);
}
}
};
});
or better
.directive('myParent', function ($timeout) {
return {
restrict: 'A', //attribute only
controller: function ($scope, $element) {
this.isDone = function(){
var context = $element[0];
var availableFormElements = 'input,textarea';
var allFormElements = context.querySelectorAll(availableFormElements);
console.log(allFormElements);
}
}
};
})
.directive('myChild', function ($timeout) {
return {
require:'^myParent',
restrict: 'A', //attribute only
link: function (scope, elem, attr, ctrl) {
if (scope.$last){
ctrl.isDone();
}
}
};
})
BTW
Don't touch the dom in the controller :)

How data is passed from custom directive view to controller?

code for the directive template
//"textBox.html"
<div class="well">
<label class="control-label">Text</label>
<div class="controls">
<input id="label" type="text" class="txt span3" ng-model="label" placeholder='Label for text field...'>
<input type="text" class="span3" ng-model="value" placeholder='Default value...'>
<input type="text" class="span3" ng-model="helpText" placeholder="Help text...">
<input type="checkbox" class="span1" ng-model="required" ng-true-value="true" ng-false-value="false">Required
<input type="checkbox" class="span1" ng-model="advanced" ng-true-value="true" ng-false-value="false">Advanced?
<img src="../../images/bullet_cross.png" alt="Remove" style="cursor: pointer" id="text" border="0" ng-click="deleteField($event)">
</div>
</div>
directive is using like this in main html page
//"algorithm.html"
<text-box></text-box>
controller for the custom directive
//"controller.js"
var algorithm = angular.module('algorithmController',[]);
/***********directive to render text field***********/
algorithm.directive('textField' , function(){
return{
restrict: 'E',
templateUrl: '../partials/algorithm/textBox.html',
require: 'ngModel',
replace: true,
link: function(scope, iElement, iAttrs, ngModelCtrl) {
// how should i get updated data(i.e. if user change after typing) over here entered by user??
}
};
});
You can create an isolate scope using the '=' syntax, which will create two way binding to your controller and the directive. You don't even necessarily need ngModel required in your directive.
.directive("textField", function () {
return {
restrict : "E",
template : "<input type='text' ng-model='val'/>",
scope : {
val : "="
}
};
});
Here is a very simple example doing what you requested;
http://jsfiddle.net/smaye81/xaohrv53/2/

Categories