how to watch changes on hidden fields with Angular? - angularjs

I have dropdown made from divs. It's not my doing, is from external agency. But this is not important. The div with a dropdown looks like this:
<label class='label-block' for='kraj-dokument'>Kraj wydania dokumentu tożsamości *</label>
<input type='hidden' name='kraj-dokument' id='kraj-dokument' value="" drop-down-validation-directive /> <div class="select kraj-dokument" data-destination="kraj-dokument">
<p class="label">Wybierz z listy</p>
<div class="options">
<p class="option" data-ng-repeat="country in countries">{{country.Name}}</p>
</div>
</div>
When you click on a choice in this dropdown an external javascript is adding th the hidden field attribute called value and it insert a text from the choise to that value. As you can see I have a directive on that hidden inputu which looks like this (after several searches, and everything):
myapp.directive("dropDownValidationDirective", function () {
return function(scope, elem, attr, ctrl) {
scope.$watch(attr['value'], function(nv) {
elem.val(nv);
}
);
}
});
The problem is when I'm doing watch nothing happens, the value is not geting watched although the change is seen when debuging this in chrome. By the way. I'm trying to also do a validation on this dropdowwn. My idea was to check if this value is filled or not and tell to the user to fill the dropdown by adding a class to it wich marks this thing red. Is that the way to do it?
UPDATE I forgot to add, and I think this is also important that the click event on that div is done with the mentioned external javascript. I'm pasting it below. I've put the external javascript functionality into the service:
myApp.service('DropDownService', function () {
this.renderDropDown = function () {
function initEvents() {
var selectClicked = $(".selectClicked");
$(".select").each(function () {
var destination = $(this).attr("data-destination");
var option = $(this).find(".option");
var options = $(this).find(".options");
var label = $(this).find(".label");
var select = $(this);
label.click(function () {
if (label.hasClass("clicked")) {
$(".select .options").hide();
$(".select .label").removeClass("clicked");
$(".select").removeClass("clicked");
selectClicked.removeClass("clicked");
} else {
$(".select .label").removeClass("clicked");
$(".select").removeClass("clicked");
label.addClass("clicked");
select.addClass("clicked");
selectClicked.addClass("clicked");
$(".select .options").hide();
options.show();
}
});
option.unbind("click").bind("click", function () {
$("#" + destination).attr("value", $(this).text());
label.text($(this).text());
options.hide();
$(".select .label").removeClass("clicked");
$(".select").removeClass("clicked");
$(".select").removeClass("error");
selectClicked.removeClass("clicked");
});
});
}
angular.element(document).ready(function () {
initEvents();
if (navigator.appVersion.indexOf("Mac") !== -1) {
$('body').addClass("MacOS");
}
});
}

Just use interpolation & attrs.$observe instead:
HTML:
<div ng-controller="AppController">
<label class="label-block" for="kraj-dokument">Kraj wydania dokumentu tożsamości *</label>
<input type="hidden" name="kraj-dokument" id="kraj-dokument" value="{{ TotalPrice }}" drop-down-validation-directive />
<div class="select kraj-dokument" data-destination="kraj-dokument" ng-click="AddItem()">
Click to change and see console output
</div>
</div>
JS:
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.Quantity = 0;
$scope.TotalPrice = 0;
$scope.Price = 100;
$scope.AddItem = function() {
$scope.Quantity++;
$scope.TotalPrice = $scope.Price * $scope.Quantity;
};
});
app.directive("dropDownValidationDirective", function() {
return {
link: function(scope, elem, attrs, ctrl) {
attrs.$observe('value', function(nv) {
console.log(nv);
});
}
}
});
Working example: http://jsfiddle.net/ghd9c8q3/56/

I'm not sure the way you're doing things is the best way, but I know why your watch doesn't do anything.
$scope.$watch() expects either a function, or an expression.
If you pass a function, it's called at each digest loop and its result is the value passed to the change listener.
If you pass an expression, it's evaluated on the scope, and the result of the evaluation is the value passed to the change listener.
So what you actually need is:
scope.$watch(function() {
return attr['value'];
}, function(nv) {
elem.val(nv);
});

Related

How can I position my cursor in an input field based on a keypress?

I am capturing keypresses like this:
<div class="contentView"
ng-keypress="phs.keyEnter($event)">
keyEnter = ($event): void => {
var a = $event;
How can I make it so that clicking a key will make the cursor go to an input field:
<input ng-change="phs.englishChange();"
ng-model="phs.english"
ng-model-options="{ debounce: 750 }"
style="width:6rem;"
type="text" />
I think directive can help us to have a more universal and re-usable solution to your problem, because it is the most good place to attach a specified behavior to that input element. So here is a custom doOnKeypress directive that accepts a key (doOnKeypress) and an optional callback (acceptOn) to check the target of the fired keypress event and a callback (onKeypress) that is going to be fired if all conditions are satisfied.
In the example below the input will be focused whenever a keyboard button is pressed. I left the comments so you can modify it for your needs (hope the general idea is clear):
angular.module("app", [])
.controller("TestController", ["$scope", function ($scope) {
$scope.acceptOn = function (target, element) {
console.log(target); // you can make any checks for target by passing this into a directive
return element[0] !== target[0]; //target is not the same input element
};
$scope.focusOn = function (element) {
element[0].focus(); // or whatever you want with element
};
}]).directive('doOnKeypress', ['$document', function ($document) {
return {
restrict: 'A',
scope: {
doOnKeypress: '#',
acceptOn: '&?',
onKeypress: '&'
},
link: function postLink(scope, element) {
function keypress(e) {
var target = angular.element(e.target);
var targetIsAcceptable = angular.isFunction(scope.acceptOn) ? scope.acceptOn({
target: target,
element: element
}) : true; // add the condition to test the target
var specialKeyPressed = e.shiftKey || e.ctrlKey || e.altKey || e.metaKey; // in case you need to check any special keys
if (targetIsAcceptable && !specialKeyPressed) {
var keyCode = e.which || e.keyCode;
var key = String.fromCharCode(keyCode);
if ("*" === scope.doOnKeypress || key.toLowerCase() === scope.doOnKeypress.toLowerCase()) { // any check before focusing (lets say * - is any key)
e.preventDefault(); // prevent from typing into the input
scope.onKeypress({element: element});
}
}
}
$document.on('keypress', keypress);
scope.$on('$destroy', function () {
$document.off('keypress', keypress);
});
}
};
}]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
<body ng-app="app" class="">
<div ng-controller="TestController" class='listen-to-keypress'>
TestController
<br/>
<div>
<input ng-change="phs.englishChange();"
ng-model="phs.english"
ng-model-options="{ debounce: 750 }"
style="width:6rem;"
do-on-keypress='A'
accept-on='acceptOn(target, element)'
on-keypress='focusOn(element)'
type="text" />
</div>
</div>
</body>
UPDATE: added element argument to the acceptOn callback to allow to compare target with the same element, since we want to let the user typing into this input element in our case.
HTML
<input value="_sample input value" ng-click="getCur_Pos($e)" ng-keyup="getCur_Pos($e)"/>
<div> Cursor Pos : <b ng-bind="curPos_Val"></b></div>
SCRIPT
$scope.getCur_Pos = function($e) {
$scope.doCar_Position($e.target);
};
$scope.doCar_Position = function(o_Fld) {
var _Crt_Pos = 0;
if (o_Fld.selectionStart || o_Fld.selectionStart == '0')
_Crt_Pos = o_Fld.selectionStart;
// Return results
$scope.curPos_Val = _Crt_Pos;
};

AngularJS - Why is the DOM not updating

So, what I am trying to do is add a "stack" - a basic JS object - into an array called cardStacks, declared the stackCtrl function. I've read that the controller in AngularJS is not supposed to do very much, nor do you want the manipulation of DOM elements done the controller. So what I have done is create a "save" directive which, as you could probably guess, adds a new "stack" into $scope.cardStacks (if the object is not being edited)
Everything seems to work ok, up until when the template is supposed to update. console.log() reveals that objects are going into an array, but because the template is not being updated, I can only guess it is not $scope.cardStacks.
Can somebody give the following a look and tell me why the template is not listing the "stacks" in the template?
Consider the following:
Template:
<div ng-controller="stackCtrl">
<stackeditor></stackeditor>
<p>Stacks:</p>
<ul class="stack-list" ng-repeat="stack in cardStacks">
<li>{{stack.title}}
<span class="stack-opts"> (Edit | Delete)</span>
</li>
</ul>
</div>
Template for the stackeditor tag/directive:
<div>
<span class="button" ng-click="show=!show">+ New</span>
<form ng-show="show" novalidate>
<input type="text" ng-model="stackTitle" required/>
<button class="button" save>Save</button>
<button class="button" reset>Cancel</button>
<div ng-show="error"><p>{{error}}</p></div>
</form>
</div>
Controller:
function stackCtrl($scope) {
$scope.cardStacks = [];
$scope.stackTitle = "";
$scope.addStack = function(title) {
var newStack = {};
newStack.title = title;
$scope.cardStacks.push(newStack);
}
$scope.removeStack = function($index) {
console.log("removing Stack...");
}
$scope.editStack = function(element) {
console.log("editing Stack...");
}
}
Directive:
fcApp.directive('save', function() {
var linkFn = function($scope, element, attrs) {
element.bind("click", function() {
if (typeof $scope.stackTitle !== 'undefined' && $scope.stackTitle.length > 0) {
if ($scope.edit) {
$scope.editStack(element);
} else {
$scope.addStack($scope.stackTitle);
}
} else {
$scope.error = "Your card stack needs a title!";
}
});
});
return {
restrict: "A",
link: linkFn
}
}
});
Try using $apply:
$scope.cardStacks.push(newStack);
$scope.$apply(function(){
$scope.cardStacks;
}
Rendering might be the problem..... Hope it helps.
The save function would be better in stackCtrl and then use ng-click in the template to call it.
You are right that manipulating the DOM in the controller is bad practice, but you are just updating an object in the controller - angular is sorting out the DOM which is fine.

AngularJS: ng-repeat list is not updated when a model element is spliced from the model array

I have two controllers and share data between them with an app.factory function.
The first controller adds a widget in the model array (pluginsDisplayed) when a link is clicked. The widget is pushed into the array and this change is reflected into the view (that uses ng-repeat to show the array content):
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div>
</div>
The widget is built upon three directives, k2plugin, remove and resize. The remove directive adds a span to the template of the k2plugin directive. When said span is clicked, the right element into the shared array is deleted with Array.splice(). The shared array is correctly updated, but the change is not reflected in the view. However, when another element is added, after the remove, the view is refreshed correctly and the previously-deleted element is not shown.
What am I getting wrong? Could you explain me why this doesn't work?
Is there a better way to do what I'm trying to do with AngularJS?
This is my index.html:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.min.js">
</script>
<script src="main.js"></script>
</head>
<body>
<div ng-app="livePlugins">
<div ng-controller="pluginlistctrl">
<span>Add one of {{pluginList.length}} plugins</span>
<li ng-repeat="plugin in pluginList">
<span>{{plugin.name}}</span>
</li>
</div>
<div ng-controller="k2ctrl">
<div ng-repeat="pluginD in pluginsDisplayed">
<div k2plugin pluginname="{{pluginD.name}}" pluginid="{{pluginD.id}}"></div>
</div>
</div>
</div>
</body>
</html>
This is my main.js:
var app = angular.module ("livePlugins",[]);
app.factory('Data', function () {
return {pluginsDisplayed: []};
});
app.controller ("pluginlistctrl", function ($scope, Data) {
$scope.pluginList = [{name: "plugin1"}, {name:"plugin2"}, {name:"plugin3"}];
$scope.add = function () {
console.log ("Called add on", this.plugin.name, this.pluginList);
var newPlugin = {};
newPlugin.id = this.plugin.name + '_' + (new Date()).getTime();
newPlugin.name = this.plugin.name;
Data.pluginsDisplayed.push (newPlugin);
}
})
app.controller ("k2ctrl", function ($scope, Data) {
$scope.pluginsDisplayed = Data.pluginsDisplayed;
$scope.remove = function (element) {
console.log ("Called remove on ", this.pluginid, element);
var len = $scope.pluginsDisplayed.length;
var index = -1;
// Find the element in the array
for (var i = 0; i < len; i += 1) {
if ($scope.pluginsDisplayed[i].id === this.pluginid) {
index = i;
break;
}
}
// Remove the element
if (index !== -1) {
console.log ("removing the element from the array, index: ", index);
$scope.pluginsDisplayed.splice(index,1);
}
}
$scope.resize = function () {
console.log ("Called resize on ", this.pluginid);
}
})
app.directive("k2plugin", function () {
return {
restrict: "A",
scope: true,
link: function (scope, elements, attrs) {
console.log ("creating plugin");
// This won't work immediately. Attribute pluginname will be undefined
// as soon as this is called.
scope.pluginname = "Loading...";
scope.pluginid = attrs.pluginid;
// Observe changes to interpolated attribute
attrs.$observe('pluginname', function(value) {
console.log('pluginname has changed value to ' + value);
scope.pluginname = attrs.pluginname;
});
// Observe changes to interpolated attribute
attrs.$observe('pluginid', function(value) {
console.log('pluginid has changed value to ' + value);
scope.pluginid = attrs.pluginid;
});
},
template: "<div>{{pluginname}} <span resize>_</span> <span remove>X</span>" +
"<div>Plugin DIV</div>" +
"</div>",
replace: true
};
});
app.directive("remove", function () {
return function (scope, element, attrs) {
element.bind ("mousedown", function () {
scope.remove(element);
})
};
});
app.directive("resize", function () {
return function (scope, element, attrs) {
element.bind ("mousedown", function () {
scope.resize(element);
})
};
});
Whenever you do some form of operation outside of AngularJS, such as doing an Ajax call with jQuery, or binding an event to an element like you have here you need to let AngularJS know to update itself. Here is the code change you need to do:
app.directive("remove", function () {
return function (scope, element, attrs) {
element.bind ("mousedown", function () {
scope.remove(element);
scope.$apply();
})
};
});
app.directive("resize", function () {
return function (scope, element, attrs) {
element.bind ("mousedown", function () {
scope.resize(element);
scope.$apply();
})
};
});
Here is the documentation on it: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply
If you add a $scope.$apply(); right after $scope.pluginsDisplayed.splice(index,1); then it works.
I am not sure why this is happening, but basically when AngularJS doesn't know that the $scope has changed, it requires to call $apply manually. I am also new to AngularJS so cannot explain this better. I need too look more into it.
I found this awesome article that explains it quite properly.
Note: I think it might be better to use ng-click (docs) rather than binding to "mousedown". I wrote a simple app here (http://avinash.me/losh, source http://github.com/hardfire/losh) based on AngularJS. It is not very clean, but it might be of help.
I had the same issue. The problem was because 'ng-controller' was defined twice (in routing and also in the HTML).
Remove "track by index" from the ng-repeat and it would refresh the DOM
There's an easy way to do that. Very easy. Since I noticed that
$scope.yourModel = [];
removes all $scope.yourModel array list you can do like this
function deleteAnObjectByKey(objects, key) {
var clonedObjects = Object.assign({}, objects);
for (var x in clonedObjects)
if (clonedObjects.hasOwnProperty(x))
if (clonedObjects[x].id == key)
delete clonedObjects[x];
$scope.yourModel = clonedObjects;
}
The $scope.yourModel will be updated with the clonedObjects.
Hope that helps.

How do I use a directive to toggle a slide animation on an element from my controller?

I am confused on the following scenario. Let's say I have a table with rows. When a user clicks a button in the table I want a user form to slide down with jQuery and display the form with the selected row values. Here is what I am currently doing that doesn't quite make sense:
View
<tr ng-click="setItemToEdit(item)" slide-down-form>
...
<form>
<input type="test" ng-model={{itemToEdit.Property1}} >
<button ng-click=saveEditedItem(item)" slide-up-form>
<form>
Control
$scope.itemToEdit = {};
$scope.setItemToEdit = function(item) {
$scope.itemToEdit = item;
});
$scope.saveEditedItem = function(item) {
myService.add(item);
$scope.itemToEdit = {};
}
Directive - Slide-Up / Slide-Down
var linker = function(scope, element, attrs) {
$(form).slideUp(); //or slide down
}
It seems the my directive and my control logic are too disconnected. For example, what happens if there is a save error? The form is already hidden because the slideUp event is complete. I'd most likely want to prevent the slideUp operation in that case.
I've only used AngularJS for about a week so I'm sure there is something I'm missing.
Sure, it's a common problem... here's one way to solve this: Basically use a boolean with a $watch in a directive to trigger the toggling of your form. Outside of that you'd just set a variable on your form to the object you want to edit.
Here's the general idea in some psuedo-code:
//create a directive to toggle an element with a slide effect.
app.directive('showSlide', function() {
return {
//restrict it's use to attribute only.
restrict: 'A',
//set up the directive.
link: function(scope, elem, attr) {
//get the field to watch from the directive attribute.
var watchField = attr.showSlide;
//set up the watch to toggle the element.
scope.$watch(attr.showSlide, function(v) {
if(v && !elem.is(':visible')) {
elem.slideDown();
}else {
elem.slideUp();
}
});
}
}
});
app.controller('MainCtrl', function($scope) {
$scope.showForm = false;
$scope.itemToEdit = null;
$scope.editItem = function(item) {
$scope.itemToEdit = item;
$scope.showForm = true;
};
});
markup
<form show-slide="showForm" name="myForm" ng-submit="saveItem()">
<input type="text" ng-model="itemToEdit.name" />
<input type="submit"/>
</form>
<ul>
<li ng-repeat="item in items">
{{item.name}}
<a ng-click="editItem(item)">edit</a>
</li>
</ul>

Reset form to pristine state (AngularJS 1.0.x)

A function to reset form fields to pristine state (reset dirty state) is on the roadmap for AngularJS 1.1.x. Unfortunately such a function is missing from the current stable release.
What is the best way to reset all form fields to their initial pristine state for AngularJS 1.0.x.?
I would like to know if this is fixable with a directive or other simple workaround. I prefer a solution without having to touch the original AngularJS sources. To clarify and demonstrate the problem, a link to JSFiddle. http://jsfiddle.net/juurlink/FWGxG/7/
Desired feature is on the Roadmap - http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html
Feature request - https://github.com/angular/angular.js/issues/856
Proposed solution Pull request - https://github.com/angular/angular.js/pull/1127
Updated with possible workaround
Good enough workaround?
I just figured out I can recompile the HTML part and put it back into the DOM. It works and it's fine for a temporarily solution, but also as #blesh mentioned in the comments:
Controllers should be used for business logic only, not for DOM!
<div id="myform">
<form class="form-horizontal" name="form">
</form>
</div>
And in my Controller on resetForm():
Save the original untouched HTML
Recompile the saved original HTML
Remove the current form from the DOM
Insert the new compiled template into the DOM
The JavaScript:
var pristineFormTemplate = $('#myform').html();
$scope.resetForm = function () {
$('#myform').empty().append($compile(pristineFormTemplate)($scope));
}
I think it's worth mentioning that in later versions of Angular (e.g. 1.1.5), you can call $setPristine on the form.
$scope.formName.$setPristine(true)
This will set all the form controls to pristine state as well.
FormController.$setPristine
Solution without a workaround
I came up with a solution which uses AngularJS without any workaround. The trick here is to use AngularJS ability to have more than one directive with the same name.
As others mentioned there is actually a pull request (https://github.com/angular/angular.js/pull/1127) which made it into the AngularJS 1.1.x branch which allows forms to be reset. The commit to this pull request alters the ngModel and form/ngForm directives (I would have liked to add a link but Stackoverflow doesn't want me to add more than two links).
We can now define our own ngModel and form/ngForm directives and extend them with the functionality provided in the pull request.
I have wrapped these directives in a AngularJS module named resettableForm. All you have to do is to include this module to your project and your AngularJS version 1.0.x behaves as if it was an Angular 1.1.x version in this regard.
''Once you update to 1.1.x you don't even have to update your code, just remove the module and you are done!''
This module also passes all tests added to the 1.1.x branch for the form reset functionality.
You can see the module working in an example in a jsFiddle (http://jsfiddle.net/jupiter/7jwZR/1/) I created.
Step 1: Include the resettableform module in your project
(function(angular) {
// Copied from AngluarJS
function indexOf(array, obj) {
if (array.indexOf) return array.indexOf(obj);
for ( var i = 0; i < array.length; i++) {
if (obj === array[i]) return i;
}
return -1;
}
// Copied from AngularJS
function arrayRemove(array, value) {
var index = indexOf(array, value);
if (index >=0)
array.splice(index, 1);
return value;
}
// Copied from AngularJS
var PRISTINE_CLASS = 'ng-pristine';
var DIRTY_CLASS = 'ng-dirty';
var formDirectiveFactory = function(isNgForm) {
return function() {
var formDirective = {
restrict: 'E',
require: ['form'],
compile: function() {
return {
pre: function(scope, element, attrs, ctrls) {
var form = ctrls[0];
var $addControl = form.$addControl;
var $removeControl = form.$removeControl;
var controls = [];
form.$addControl = function(control) {
controls.push(control);
$addControl.apply(this, arguments);
}
form.$removeControl = function(control) {
arrayRemove(controls, control);
$removeControl.apply(this, arguments);
}
form.$setPristine = function() {
element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
form.$dirty = false;
form.$pristine = true;
angular.forEach(controls, function(control) {
control.$setPristine();
});
}
},
};
},
};
return isNgForm ? angular.extend(angular.copy(formDirective), {restrict: 'EAC'}) : formDirective;
};
}
var ngFormDirective = formDirectiveFactory(true);
var formDirective = formDirectiveFactory();
angular.module('resettableForm', []).
directive('ngForm', ngFormDirective).
directive('form', formDirective).
directive('ngModel', function() {
return {
require: ['ngModel'],
link: function(scope, element, attrs, ctrls) {
var control = ctrls[0];
control.$setPristine = function() {
this.$dirty = false;
this.$pristine = true;
element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
}
},
};
});
})(angular);
Step 2: Provide a method on your controller which resets the model
Please be aware that you must reset the model when you reset the form. In your controller you can write:
var myApp = angular.module('myApp', ['resettableForm']);
function MyCtrl($scope) {
$scope.reset = function() {
$scope.form.$setPristine();
$scope.model = '';
};
}
Step 3: Include this method in your HTML template
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<form name="form">
<input name="requiredField" ng-model="model.requiredField" required/> (Required, but no other validators)
<p ng-show="form.requiredField.$errror.required">Field is required</p>
<button ng-click="reset()">Reset form</button>
</form>
<p>Pristine: {{form.$pristine}}</p>
</div>
</dvi>
EDIT... I'm removing my old answer, as it was not adequate.
I actually just ran into this issue myself and here was my solution: I made an extension method for angular. I did so by following a bit of what $scope.form.$setValidity() was doing (in reverse)...
Here's a plnkr demo of it in action
Here's the helper method I made. It's a hack, but it works:
angular.resetForm = function (scope, formName, defaults) {
$('form[name=' + formName + '], form[name=' + formName + '] .ng-dirty').removeClass('ng-dirty').addClass('ng-pristine');
var form = scope[formName];
form.$dirty = false;
form.$pristine = true;
for(var field in form) {
if(form[field].$pristine === false) {
form[field].$pristine = true;
}
if(form[field].$dirty === true) {
form[field].$dirty = false;
}
}
for(var d in defaults) {
scope[d] = defaults[d];
}
};
Hopefully this is helpful to someone.
Your form fields should be linked to a variable within your $scope. You can reset the form by resetting the variables. It should probably be a single object like $scope.form.
Lets say you have a simple form for a user.
app.controller('Ctrl', function Ctrl($scope){
var defaultForm = {
first_name : "",
last_name : "",
address: "",
email: ""
};
$scope.resetForm = function(){
$scope.form = defaultForm;
};
});
This will work great as long as your html looks like:
<form>
<input ng-model="form.first_name"/>
<input ng-model="form.last_name"/>
<input ng-model="form.address"/>
<input ng-model="form.email"/>
<button ng-click="resetForm()">Reset Form</button>
</form>
Maybe I'm not understanding the issue here, so if this does not address your question, could you explain why exactly?
Here I have found a solution for putting the from to its pristine state.
var def = {
name: '',
password: '',
email: '',
mobile: ''
};
$scope.submited = false;
$scope.regd = function (user) {
if ($scope.user.$valid) {
$http.post('saveUser', user).success(function (d) {
angular.extend($scope.user, def);
$scope.user.$setPristine(true);
$scope.user.submited = false;
}).error(function (e) {});
} else {
$scope.user.submited = true;
}
};
Just write angular.extends(src,dst) ,so that your original object is just extends the blank object, which will appear as blank and rest all are default.
Using an external directive and a lot of jquery
app.controller('a', function($scope) {
$scope.caca = function() {
$scope.$emit('resetForm');
}
});
app.directive('form', function() {
return {
restrict: 'E',
link: function(scope, iElem) {
scope.$on('resetForm', function() {
iElem.find('[ng-model]').andSelf().add('[ng-form]').each(function(i, elem) {
var target = $(elem).addClass('ng-pristine').removeClass('ng-dirty');
var control = target.controller('ngModel') || target.controller('form');
control.$pristine = true;
control.$dirty = false;
});
});
}
};
});
http://jsfiddle.net/pPbzz/2/
The easy way: just pass the form into the controller function. Below the form "myForm" is referenced by this, which is equivalent to $scope.
<div ng-controller="MyController as mc">
<ng-form name="myform">
<input ng-model="mc.myFormValues.name" type="text" required>
<button ng-click="mc.doSometing(this.myform)" type="submit"
ng-disabled="myform.$invalid||myform.$pristine">Do It!</button>
</ng-form>
</div>
The Controller:
function MyController(MyService) {
var self = this;
self.myFormValues = {
name: 'Chris'
};
self.doSomething = function (form) {
var aform = form;
MyService.saveSomething(self.myFromValues)
.then(function (result) {
...
aform.$setPristine();
}).catch(function (e) {
...
aform.$setDirty();
})
}
}

Resources