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
Related
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
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?
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
var app = angular.module('formExample', []);
app.controller('FormCtrl', function ($scope, $http) {
$scope.data = {};
$scope.submitForm = function() {
formData = $scope.regform;
console.log("posting data....");
$http({ url: '/',data: $scope.regform, method: 'post' }).success();
console.log(formData);
};
$scope.reset = function(form) {
if (form) {
form.$setPristine();
form.$setUntouched();
}
$scope.user = angular.copy($scope.data);
};
$scope.reset();
});
This is my JavaScript code. It submit form along with validation. I need only submit form after validation done. And the reset button not working properly.
Click here plnkr example
you can rather create a directive for this purpose
code below answer is copied from here, (copy pasted as link only answers are not allowed)...
var app = angular.module('plunker', []);
var ValidSubmit = ['$parse', function ($parse) {
return {
compile: function compile(tElement, tAttrs, transclude) {
return {
post: function postLink(scope, element, iAttrs, controller) {
var form = element.controller('form');
form.$submitted = false;
var fn = $parse(iAttrs.validSubmit);
element.on('submit', function(event) {
scope.$apply(function() {
element.addClass('ng-submitted');
form.$submitted = true;
if(form.$valid) {
fn(scope, {$event:event});
}
});
});
}
}
}
}
}]
app.directive('validSubmit', ValidSubmit);
and then in html
<form class="form-horizontal" role="form" name="form" novalidate valid-submit="connect()">
<div class="form-group">
<div class="input-group col col-sm-11 col-sm-offset-1">
<span class="input-group-addon input-large"><i class="glyphicon glyphicon-envelope"></i></span>
<input class="input-large form-control" type="email" id="email" placeholder="Email" name="email" ng-model="email" required="required">
</div>
<p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.required">please enter your email</p>
<p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.email">please enter a valid email</p>
</div>
</form>
The PLUNKER LINK to check this
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 :)