using $watch in angularjs - javascript

I have a form with 2 input fields and requirement is that once user enters valid data into these
fields, I need to pass the input data to the factory function and get the data from server.To achieve this I thought of using $watch function but stuck at how to know if form is valid in $wathc function and then call the factory function to get data from the server.Here is the code.
Any help would be highly appreciated.
//html
<html>
<body ng-app="myModule">
<div ng-controller="myCtrl">
Product Id: <input type="text" ng-model="myModel.id" /><br/>
Product Name: <input type="text" ng-model="myModel.productname" /><br/>
</div>
</body>
</html>
//js
var myModule = angular.module('myModule',[]);
myModule.controller('myCtrl',['$scope', function($scope){
$scope.myModel = {};
var getdata = function(newVal, oldVal) {
};
$scope.$watch('myModel.id', getdata)
$scope.$watch('myModel.productname', getdata)
}]);

Wouldn't you just watch myModel, since the same function is called in both cases?

You could do this with ng-change just as easily.
<html>
<body ng-app="myModule">
<form name="productForm" ng-controller="myCtrl">
<div>
Product Id: <input type="text" name="idModel" ng-model="myModel.id" ng-change="validateID()" /><br/>
Product Name: <input type="text" ng-model="myModel.productname" ng-change="validateProduct()" /><br/>
</div>
</form>
</body>
And your JS would look like this:
var myModule = angular.module('myModule',[]);
myModule.controller('myCtrl',['$scope', 'myFactory',
function($scope, myFactory){
$scope.myModel = {};
$scope.validateID = function(){
//things that validate the data go here
if(your data is valid){
myFactory.get(yourParams).then(function(data){
//whatever you need to do with the data goes here
});
}
};
$scope.validateProduct = function(){
//things that validate the data go here
if(your data is valid){
myFactory.get(yourParams).then(function(data){
//whatever you need to do with the data goes here
});
}
};
}
]);
Using ng-change saves you from having to add a $watch to your scope (they are expensive) and will fire when the user leaves the input box. If you need to catch each keystroke, I would recommend that you use UI-Keypress and run the same functions.

To know if form is valid you have to add a form tag and inside your controller check $valid, on your example the form is always valid becaus you do not have any required field.
See the below example on codepen
The HTML
<div ng-app="myModule">
<div ng-controller="myCtrl">
<form name="myform" novalidate>
Product Id:
<input type="text" ng-model="myModel.id" />
<br/>
Product Name:
<input type="text" ng-model="myModel.productname" />
<br/>
</form>
<br/>
<div>{{result}}</div>
<div>Form is valid: {{myform.$valid}}</div>
</div>
</div>
The JS
var myModule = angular.module('myModule', []);
myModule.controller('myCtrl', ['$scope', function ($scope) {
$scope.myModel = {};
$scope.result = "(null)";
var getdata = function (newVal, oldVal) {
var valid = null;
if ($scope.myform.$valid) {
valid = "is valid";
} else {
valid = "is INVALID";
}
$scope.result = "Changed value " + newVal + " form " + valid;
};
$scope.$watch('myModel.id', getdata);
$scope.$watch('myModel.productname', getdata);
}]);

Related

Function treated as string in Angular JS

I have an html form that takes a name and a location and Posts it to a mobile service table.
<form name="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" /></p>
<p>location: <input type="text" id="location" ng-model="user.location"/></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
and this is how I retrieve data from the form in Angular
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function (theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
},
location: function (theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}};
however, when I run the html, the location textbox has the function code instead of the "Default Location" string, and the name textbox is blank instead of "Default Name".
I wonder what can be wrong here. Any help is appreciated.
AngularJS works correct. It basically takes the string representation of the function, and sets it as the value of the textbox.
If you need the evaluated value instead, you need to call the function by putting a parentheses after the function name, like this:
angular.module('myapp', [])
.controller('myctrl', function($scope) {
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function(theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
}(),
location: function(theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}()
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
<form name="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" /></p>
<p>location: <input type="text" id="location" ng-model="user.location" /></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
</div>
You can set directly the default value to the model like this:
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = { //set default value to the inputs
name:$scope._name,
location:$scope._location
}
If you are using latest version of angular js. Try ng-model-options="{ getterSetter: true }".
Sometimes it's helpful to bind ngModel to a getter/setter function. A
getter/setter is a function that returns a representation of the model
when called with zero arguments, and sets the internal state of a
model when called with an argument. It's sometimes useful to use this
for models that have an internal representation that's different from
what the model exposes to the view.
Best Practice: It's best to keep getters fast because AngularJS is
likely to call them more frequently than other parts of your code. You
use this behavior by adding ng-model-options="{ getterSetter: true }"
to an element that has ng-model attached to it. You can also add
ng-model-options="{ getterSetter: true }" to a , which will
enable this behavior for all s within it. See ngModelOptions
for more.
angular.module('myapp', [])
.controller('myctrl', function($scope) {
$scope.people = [];
$scope._name = "Default Name";
$scope._location = "Default Location";
$scope.user = {
name: function(theName) {
if (angular.isDefined(theName)) {
$scope._name = theName;
}
return $scope._name;
},
location: function(theLocation) {
if (angular.isDefined(theLocation)) {
$scope._location = theLocation;
}
return $scope._location;
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
<form name="userform" ng-submit="addName(user)">
<p>name: <input type="text" id="name" ng-model="user.name" ng-model-options="{ getterSetter: true }"/></p>
<p>location: <input type="text" id="location" ng-model="user.location" ng-model-options="{ getterSetter: true }"/></p>
<button id="btn-add-evangelist">Add to list</button>
</form>
</div>

Form does not update on view and server in AngularJS?

I have this bug in my web app. So, I have a form where when I edit the form it does not update on view and server. What I want to solve is when I edit my form, I want to update the view and the server. So, here is my code below. Please, check out my code if somethings wrong. Thanks in advance. Any Help?
here is my code.
var app = angular.module("MyApp", ['ngRoute', 'ui.bootstrap']);
app.controller('MyCtrl', function($scope, $window, people) {
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
});
$scope.inactive = true;
$scope.updateUser = function(person) {
people.updateUser(person);
};
$scope.confirmedAction = function(person) {
var index = $scope.userInfo.lawyers.map(function(e) {
return e.id;
}).indexOf(person.id);
people.confirmUser(person.id).then(function(data){ });
$scope.userInfo.lawyers.splice(index, 1);
console.log($scope.userInfo.lawyers);
$window.location.href = '#/lawyer';
};
});
});
about
<div ng-controller="MyCtrl">
<div ng-repeat="person in userInfo.lawyers | filter : {id: lawyerId}">
<a class="back" href="#/lawyer">Back</a>
<button type="button" class="edit" ng-show="inactive" ng-click="inactive = !inactive">
Edit
</button>
<button type="submit" class="submit" ng-show="!inactive" ng-click="updateUser(person)">Save</button>
<a class="delete" ng-click="confirmedAction(person);" confirm-click>Confirm</a>
<div class="people-view">
<h2 class="name">{{person.firstName}}</h2>
<h2 class="name">{{person.lastName}}</h2>
<span class="title">{{person.email}}</span>
<span class="date">{{person.website}}</span>
</div>
<div class="list-view">
<form>
<fieldset ng-disabled="inactive">
<legend>Info</legend>
<b>First Name:</b>
<input type="text" ng-model="person.firstName">
<br>
<b>Last Name:</b>
<input type="text" ng-model="person.lastName">
<br>
<b>Email:</b>
<input type="email" ng-model="person.email">
<br>
<b>Website:</b>
<input type="text" ng-model="person.website">
<br>
</fieldset>
</form>
</div>
</div>
</div>
services to my backend
app.factory('people', function ($http) {
var service = {};
service.getUserInfo = function () {
return $http.get('https://api-dev.mysite.com/admin/v1/lawyers');
};
service.confirmUser = function (lawyerId) {
return $http.put('https://api-dev.mysite.com/admin/v1/lawyers/'+lawyerId+'/confirm');
};
service.updateUser = function (person) {
return $http.put('https://api-dev.mysite.com/admin/v1/lawyers/'+ person.id, person);
};
return service;
});
HomeController
var isConfirmed = false;
app.controller('HomeController', function($scope, people) {
if (!isConfirmed) {
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
}, function (error) {
console.log(error)
});
}
});
There are a couple of problems here.
Data from the server is not bound to the controller which means it will not display in your view.
The inputs to your form are binding to aliases and not any members of an actual scope
After you submit changes to your data, you need to get updates from your server
The inactive scope value is not updated after you save your data
which means your 'Save' button won't hide after a form is submitted.
First step is populating your $scope.userInfo in your MyCtrl controller. When you set $scope.userInfo in your HomeController only HomeController has access to $scope.userInfo and not MyCtrl.
You need to change your code such that MyCtrl sets $scope.userInfo in it's own scope so that it has access to the data like so:
app.controller('MyCtrl', function($scope, $window, people) {
// This function will now be called so that it can get the userInfo
// from the server and populate into the scope and give the controller
// access.
people.getUserInfo().then(function (response) {
$scope.userInfo = response.data;
});
// ...
});
Now you need to actually bind the input of your form to the data in your scope.
<form>
<fieldset ng-disabled="inactive">
<legend>Info</legend>
<b>First Name:</b>
<input type="text" ng-model="userInfo.lawyers[$index].firstName">
<br>
<b>Last Name:</b>
<input type="text" ng-model="userInfo.lawyers[$index].lastName">
<br>
<b>Email:</b>
<input type="email" ng-model="userInfo.lawyers[$index].email">
<br>
<b>Website:</b>
<input type="text" ng-model="userInfo.lawyers[$index].website">
<br>
</fieldset>
</form>
It's important to remember that Angular needs to bind to data in $scope before it will render changes in the DOM and using person from the person in userInfo.lawyers ng-repeat directive references an alias to a person and not to the actual data in the userInfo scope.
After you submit your changes you're going to want to update your list with new data from the server so include:
app.controller('MyCtrl', function($scope, $window, people) {
// ...
$scope.updateUser = function(person) {
people.updateUser(person)
// Now get the new data.
.then(function() {
return people.getUserInfo();
}).then(function (response) {
// Apply the new data to the scope.
$scope.userInfo = response.data;
});
};
// ...
});
Finally for the Save button issues you need to be sure that isactive value of the scope is set appropriately for when you do and don't want it to appear in the DOM. Setting the value to true hides it while setting to false reveals it. The edit button already toggles this value for you but you can also toggle this value when the function you want it to execute completes. You can do this in the updateUser function:
app.controller('MyCtrl', function($scope, $window, people) {
// ...
$scope.updateUser = function(person) {
// Hide the save button
$scope.inactive = true;
people.updateUser(person)
.then(function() {
return people.getUserInfo();
}).then(function (response) {
$scope.userInfo = response.data;
});
};
// ...
});
Additional resources for AngularJS scopes can be found here.

Getting data from the HTML form into JavaScript

I am trying to get the values from the form inputs once you click submit into variables in JavaScript.
However I don't seem to be having much luck as the console log just shows the variables as empty.
HTML
<html>
<head>
<meta charset="UTF-8">
<title>Registration</title>
</head>
<body>
<fieldset><legend>Registration</legend>
<form action="#" method="post" id="theForm">
<label for="username">Username<input type="text" name="username" id="username"></label>
<label for="name">Name<input type="text" name="name" id="name"></label>
<label for="email">Email<input type="email" name="email" id="email"></label>
<label for="password">Password<input type="password" name="password" id="password"></label>
<label for="age">Age<input type="number" name="age" id="age"></label>
<input type="hidden" name="unique" id="unique">
<input type="submit" value="Register!" id="submit">
</form>
</fieldset>
<div id="output"></div>
<script src="js/process.js"></script>
</body>
</html>
JS
var output = document.getElementById('output');
function addUser() {
'use strict';
var username = document.getElementById('username');
var name = document.getElementById('name');
var email = document.getElementById('email');
var password = document.getElementById('password');
var age = document.getElementById('age');
console.log(username.value);
console.log(name.value);
console.log(password.value);
}
// Initial setup:
function init() {
'use strict';
document.getElementById('theForm').onsubmit = addUser();
} // End of init() function.
//On window load call init function
window.onload = init;
EDIT It was because I needed to remove () on addUser and also add return false to the addUser function at the bottom.
In
function init() {
'use strict';
document.getElementById('theForm').onsubmit = addUser();
}
This will set the onsubmit equal to undefined because addUser returns nothing.
To get the function addUser as the onsubmit function use this instead.
function init() {
'use strict';
document.getElementById('theForm').onsubmit = addUser;
}
You are trying to pass the function itself not the return of it.
Also, when I'm making functions that will be passed or set, I find it more reasonable to write them like this:
var addUser = function(){
...
}
In order to make your function working, you might want to do this:
function init() {
'use strict';
document.getElementById('theForm').onsubmit = function () { addUser(); }
}
You can refer to the post below for further explanation:
Timing of button.onclick execution
Hope it helps!

How to pass value of textbox to a method in controller?

In Angularjs, I'm trying to pass a value from a textbox to method written in controller as below
#Try 1
<input type="text" ng-blur="isExists(this.value)">
and within my controller I have
$scope.isExists = function (theValue) {
alert(theValue);
};
It is not working.
#Try 2
<input type="text" ng-model="username" ng-blur="isExists()">
and within controller
$scope.isExists = function () {
alert($scope.username); // returns undefined
};
How to pass value from ng-blur to a method within a Controller?
Updates:
Any reason why the valueis not seen in the textbox?
<input type="text" ng-model="username" ng-blur="isExists()">
Fiddle
Try2 should not return undefined if the <input type="text"
is filled with at least one character.
You can append {{ username }} on the html page just for debug purporses to make sure it was well binded.
<input type="text" name="userId" id="txtid" />
<script type="text/javascript">
$(document).ready(function () {
$('#txtid').blur(function () {
debugger;
var id = $('#txtid').val();
window.location = "/Home/CreateSupplier/?userid=" + id;
});
});
</script>
In controller
public ActionResult CreateSupplier(string userid)
{
if (userid != null)
{
return Content("Received Username:" + userid);
}
return View(thesupplierList);
}

Trigger NgChecked in Angular JS

I need to work out a way of triggering NgChecked to re-evaluate it's expression after a user submits a form (which reloads the data). Ideally the trigged would be after the data has been reloaded, so the checkbox state is in line with that of the data and the amendments that have been made.
I've tried calling the expression directly after loadData() is called, however to no avail.
Do I instead need to use something like NgUpdate?
Any suggestions would be very much appreciated. Please see my code below:
view.html
<form ng-submit="updateinfo(item.downloadID); showDetails = ! showDetails;">
<input class="form-control" style="margin:5px 3px;" type="text"
ng-model="item.title" value="{{item.title}}"
placeholder="{{item.title}}"/>
<div class="checkbox" style="margin:5px 3px;">
<label for="downloadLive">
<input name="downloadLive" type="checkbox" ng-model="item.dlLive" ng-checked="liveCheckBoxState(item.dlLive);" ngTrueValue="1" ngFalseValue ="0"> Download live
</label>
</div>
<input class="btn btn-default form-control" style="margin:5px 3px;" type="submit"/>
</form>
controllers.js
// a scope function to edit a record
$scope.updateinfo = function(downloadID) {
id = downloadID
var result = $scope.items.filter(function( items ) {
return items.downloadID == id;
});
updatedata = $scope.items
$http({
method : 'PUT',
url : '/view1/downloadedit/'+id,
data : result
});
$scope.loadData();
};
//return correct state checkbox for downloadlive
$scope.liveCheckBoxState = function(dlLive) {
console.log(dlLive);
if (dlLive == 1) {
return true;
} else {
return false;
};
};
// a scope function to load the data
$scope.loadData = function () {
$http.get('/view1/downloadData').success(function (data) {
$scope.items = data;
});
};
$scope.loadData();

Categories