Angular ng-model values not registered on submit - javascript

I know the title is kind of ambiguous but here is the issue: I have 2 input fields in a form that look like this:
<form name="modifyApp" class="form-signin" ng-submit="modify(val)">
<input type="text" class="form-control" ng-model="val.name" id="appName">
<input type="number" class="form-control" ng-model="val.number" id="number" min="0" max="65535">
<button type="submit">Submit</button>
</form>
When I load the page I populate those two with some values from inside the controller:
angular.module('myApp').controller('modifyAppController', ['$scope', function($scope) {
function setFields(appName, appNumber){
document.getElementById("appName").value = appName
document.getElementById("number").value = appNumber
}
$scope.modify= function(val){
console.log(val)
}
}])
The problem is when I press the Submit button. The values won't get registered unless I change them. For example, if I press the Submit button nothing gets printed, but if I change the number or the name, it gets printed.

In your controller you can simply initialize the val object like this:
angular.module('myApp', [])
.controller('modifyAppController', ['$scope', function($scope) {
$scope.val = {
name: '',
number: 0
};
function setFields(appName, appNumber) {
$scope.val.name = appName;
$scope.val.number = appNumber;
}
$scope.modify = function(val) {
console.log(val);
};
}]);

You need to rewrite your controller:
angular.module('myApp').controller('modifyAppController', ['$scope', function($scope) {
$scope.val = {
name = 'My app name',
number = '1'
};
function setFields(appName, appNumber){
$scope.val.name = appName;
$scope.val.number = appNumber;
}
$scope.modify= function(){
console.log($scope.val);
}
}])
You don't need to directly modify the DOM values in Angular. All your $scope variables are available in your template.

why not just have the following as the first line in your form
<form name="modifyApp" class="form-signin" ng-submit="modify()">
and then your controller can look like this
$scope.val = {
name: '',
number:0//some default values
}
$scope.modify= function(){
console.log($scope.val)
}

Related

AngularJS: How to get changed key and value from existing object in form?

I've an object which contains 100 keys, value pairs.
$scope.obj = {
key1: value1,
key1: value1,
.
.
.
key100: value100
}
I have 100 inputs
<form>
<input value="obj.key1" ng-model="obj.key1" />
<input value="obj.key2" ng-model="obj.key2" />
<input value="obj.key3" ng-model="obj.key3" />
.
.
.
<input value="obj.key100" ng-model="obj.key100" />
<button ng-click="submit> </button>
</form>
When I sumbit the data will send to server. Some time I'll change values and sometimes not. If I change a value in one input I want that key,value from object. So that I can send server call with that data not to send entire data.
I would achieve this by using the default ngForm directives like $dirty and a "save state" object of your original input values. This is a easy solution to achieve what you want. ngForm itself does not provide the original values so you have to create a "save object" and compare them manually.
View
<div ng-controller="MyCtrl">
<form name="myForm" ng-submit="submit()">
<input type="text" name="key1" ng-model="obj.key1"><br />
<input type="text" name="key2" ng-model="obj.key2"><br />
<input type="text" name="key3" ng-model="obj.key3">
<input type="submit" id="submit" value="Submit" />
</form>
</div>
AngularJS application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.obj = {
key1: 'test 1',
key2: 'test 2',
key3: 'test 3',
}
var originalValues = angular.copy($scope.obj);
$scope.submit = function () {
var paramsChanged = {};
angular.forEach($scope.obj, function (value, key) {
if ($scope.myForm[key].$dirty && originalValues[key] !== value) {
paramsChanged[key] = value;
}
});
console.log(paramsChanged);
}
});
> demo fiddle
Have a copy of the variable and just before sending it to the server, compare the model object with the copied variable using a compare function like the following:
// At the time of initialization
$scope.obj = [ ... ];
var copiedObj = angular.copy($scope.obj);
// At the time of submit
var changed = {};
Object.keys(copiedObj).forEach(key => {
if(copiedObj[key] !== $scope.obj[key]) {
changed[key] = $scope.obj[key];
}
});
// Submit `changed` to the server
Assuming copiedObj is the copy of original $scope.obj, changed will contain the keys which are actually changed. So you can send changed to the server.
You can use $watch to watch for specific changes in $scope.
$scope.$watch('obj.key1', function(newValue, oldValue) {
console.log('Key1 was updated from' + oldValue + ' to ' + newValue');
});
You can do this way have a ng-change bind to your HTML and whenever the ng-change happens for a particular Element write a code to push into an array and send that array to the server.
A sample Code
<input value="obj.key100" ng-model="obj.key100" ng-change="selectedValue(obj.keyx)" />
Angular Code
$scope.tempValues=[];
$scope.selectedValue = function(x) {
$scope.tempValues.push(x);
}
You can use ng-change to detect any changes, as well as a (key, value) syntax in ng-repeat to list your inputs. Here is a demo:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.obj = {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
var toSend = [];
$scope.select = function(key) {
var s = {};
s[key] = $scope.obj[key]
toSend.push(s); // or just the value: $scope.obj[key]
}
$scope.submit = function() {
console.log(toSend)
$scope.sent = toSend;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form ng-submit="submit()">
<div ng-repeat="(key,value) in obj">
<input ng-change="select(key)" ng-model="value" /><br>
</div>
<button type="submit">Send</button>
</form>
<pre>{{sent | json}}</pre>
</div>

How to bind a value from one ng-model to an other by matching a specific string

I got a requirement to bind a value to a particular model when the value in the other model contains a string starting with "https".
For example, I have two text fields both fields having different model
<input type="text" ng-model="modelText1">
<input type="text" ng-model="modelText2">
Suppose I type a value on the first text field "https", the first input model modelText1 have to bind to the second input model modelText2 and later on i have to maintain it as like two-way binding. i.e. the second field will automatically get the value dynamically when it contains "https" at starting of a string.
Try it like in this Demo fiddle.
View
<div ng-controller="MyCtrl">
<input type="text" ng-model="modelText1">
<input type="text" ng-model="modelText2">
</div>
AngularJS Application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.modelText1 = '';
$scope.modelText2 = '';
var regEx = new RegExp(/^https/);
$scope.$watch('modelText1', function (newValue) {
if (newValue.toLowerCase().match(regEx)) {
$scope.modelText2 = newValue;
} else {
$scope.modelText2 = '';
}
});
});
An other approach is (that avoid using of $watch) is to use AngularJS ng-change like in this
example fiddle.
View
<div ng-controller="MyCtrl">
<input type="text" ng-model="modelText1" ng-change="change()">
<input type="text" ng-model="modelText2">
</div>
AngularJS Application
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.modelText1 = '';
$scope.modelText2 = '';
var regEx = new RegExp(/^https/);
$scope.change = function () {
if ($scope.modelText1.toLowerCase().match(regEx)) {
$scope.modelText2 = $scope.modelText1;
} else {
$scope.modelText2 = '';
}
};
});
You can use the ng-change directive like this:
<input type="text" ng-model="modelText1" ng-change="onChange()">
<input type="text" ng-model="modelText2">
and your controller:
$scope.onChange = function() {
if ($scope.modelText1 === 'https') {
$scope.modelText2 = $scope.modelText1;
else
$scope.modelText2 = '';
};
use ng-change to check the text is equal to 'https'
angular.module('app',[])
.controller('ctrl',function($scope){
$scope.changeItem = function(item){
$scope.modelText2 = "";
if(item.toLowerCase() === "https"){
$scope.modelText2 = item
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="modelText1" ng-change="changeItem(modelText1)">
<input type="text" ng-model="modelText2">
</div>
EDiTED
to make sure it does't fail under 'HTTPS' use toLoweCase function to make all lower case
HTML :
<input type="text" ng-model="modelText1" ng-change="updateModal(modelText1)">
JS :
var modelText1 = $scope.modelText1.toLowerCase();
$scope.updateModal = function(){
$scope.modelText2 = '';
if(modelText1.indexOf('https')!=-1){
$scope.modelText2 = modelText1;
}
}
you could also possibly do this as a directive if you want to have a more reusable solution over multiple views http://jsfiddle.net/j5ga8vhk/7/
It also keeps the controller more clean, i always try to use the controller only for controlling complex business logic and business data
View
<div ng-controller="MyCtrl">
<input type="text" ng-model="modelText1" >
<input type="text" ng-model="modelText2" model-listener="modelText1" model-listener-value="https" >
</div>
Angular JS
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function ($scope) {
$scope.modelText1 = '';
$scope.modelText2 = '';
});
myApp.directive('modelListener', [function() {
return {
restrict: 'A',
controller: ['$scope', function($scope) {
}],
link: function($scope, iElement, iAttrs, ctrl) {
$scope.$watch(iAttrs.modelListener, function() {
if($scope[iAttrs.modelListener] === iAttrs.modelListenerValue ) {
$scope[iAttrs.ngModel] = $scope[iAttrs.modelListener];
} else {
$scope[iAttrs.ngModel] = "";
}
}, true);
}
};
}]);

Service Function Not Being Triggered

I have a controller which works fine toggling hide and show on a div element at this stage I am trying to clean up so I started using a service.
Controller Snippet with toggle method inside
app.controller('addFormCtrl', function($scope, $http, $timeout, Service){
$scope.myVar = true
$scope.toggle = function (){
$scope.myVar = !$scope.myVar
//once toggled i.e form taken away success or failure message displayed for x time
$scope.successOrFailureAlert = true;
$timeout(function () {$scope.successOrFailureAlert = false}, 2000)
}
})
Service
app.service('Service', function($timeout){
var user = ""
var location = ""
this.toggle = function(var1,var2){
console.log(var1)
console.log(var2)
var1 = !var1
var2 = true;
$timeout(function () {var2 = false}, 2000)
}
})
Controller with service added
app.controller('addFormCtrl', function($scope, $http, $timeout, Service){
$scope.myVar = true
$scope.toggle = Service.toggle($scope.myVar, $scope.successOrFailureAlert)
//function (){
// $scope.myVar = !$scope.myVar
// once toggled i.e form taken away success or failure message displayed for x time
// $scope.successOrFailureAlert = true;
// $timeout(function () {$scope.successOrFailureAlert = false}, 2000)
//}
})
When I use the service instead of defining the method there. nothing happens the toggle dosen't fire. I wish I had more to add in regards to contextual information
HTML
<div ng-controller="addFormCtrl">
<span ng-show="successOrFailureAlert"> {{status}} </span>
<button ng-click="toggle()"> Add Employee </button>
<form ng-hide="myVar" ng-submit="submitAddEmployeeForm()">
<input type="text" ng-model="name">
<input type="text" ng-model="country">
<input type="submit" value="Submit" />
</form>
</div>
Call it inside a function, because your ng-click expects a function.
$scope.toggle = function(){
Service.toggle($scope.myVar, $scope.successOrFailureAlert);
}

Setting data-ng-model in JavaScript

I need to set the data-ng-model attribute of an html input field via javascript.
I know I can't do
element.data-ng-model = "...";
because of the dashes. So I tried
element.["data-ng-model"] = "...";
and
element.dataNgModel = "...";
and
element.datangmodel = "...";
None of these seem to work properly.
Any suggestions?
Try:
element.setAttribute("ng-model", "...");
or if you have JQuery:
$(element).attr("ng-model", "...");
If you need to set the model with javascript you can set it in the controller see below From the angular docs
https://docs.angularjs.org/api/ng/directive/ngModel
(function(angular) {
'use strict';
angular.module('getterSetterExample', [])
.controller('ExampleController', ['$scope',
function($scope) {
var _name = 'Brian';
$scope.user = {
name: function(newName) {
// Note that newName can be undefined for two reasons:
// 1. Because it is called as a getter and thus called with no arguments
// 2. Because the property should actually be set to undefined. This happens e.g. if the
// input is invalid
return arguments.length ? (_name = newName) : _name;
}
};
}
]);
})(window.angular);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<div ng-app="getterSetterExample">
<div ng-controller="ExampleController">
<form name="userForm">
<label>Name:
<input type="text" name="userName" ng-model="user.name" ng-model-options="{ getterSetter: true }" />
</label>
</form>
<pre>user.name = <span ng-bind="user.name()"></span></pre>
</div>
</div>

how to change value based on user input, in angular?

I am trying to change the output value based on the user input, using angular. I can increment the value, however, when an input changes, the outputed value doesn't change
Here is my code:
<input type="text" ng-change="myFunc()" ng-model="myValue" />
<p>You have {{total}} points left.</p>
</div>
<script>
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.myValue = 0;
$scope.total = 5;
$scope.myFunc = function() {
$scope.total -= $scope.myValue;
};
}]);
</script>
I want it that when the user, clicks, for instance, backspace, the total goes back to its initial value (which in this example, is 5)
any ideas?
I think it is simplier to do
<input type="text" ng-model="myValue" />
<p>You have {{total - myValue}} points left.</p>
<button type="button" ng-click="myFunc()">
<script>
angular.module('myApp', [])
.controller('myCtrl', ['$scope', function($scope) {
$scope.myValue = 0;
$scope.total = 5;
$scope.myFunc = function() {
$scope.total-=$scope.myValue;
};
}]);
</script>
Like this, user can see the value but apply it only with an explicit action
If you want to get back to the initial value, you can check the input length.
$scope.myFunc = function() {
if(!$scope.myValue.length){
$scope.total = 5;
}
$scope.total-=$scope.myValue;
}
http://jsfiddle.net/ugmv5od1/
I think in your change function you should have this. Add a scope.initial as the starting value rather than total, so you can go back to it when nothing is in the box.
$scope.initial=5;
$scope.myValue=0;
$scope.total = $scope.initial;
$scope.myFunc = function(){
$scope.total = $scope.initial - myValue;
}

Categories

Resources