AngularJS - ngRepeat - Error message on all elements - angularjs

I have the following AngularJS code, where I loop through the object array using ngRepeat. I have a validation for the numeric field. The issue that I face is that, even if one record's validation fail, the error message is thrown for all records. I am not sure where is the issue.
JSFiddle Link - http://jsfiddle.net/jdev_hari/kduh4h5p/5/
Controller Code
var app = angular.module('myapp', [], function () {});
app.controller('AppController', function ($scope) {
$scope.scholarships = [
{
"name" : "abc",
"amount" : "456"
},
{
"name" : "def",
"amount" : "789"
}
];
});
HTML Code
<div ng-repeat="scholarship in scholarships">
{{scholarship.name}}
<input type="text" id="sAmount-{{$index}}" max="500" ng-model="scholarship.amount" required/>
<div ng-show="scholarship-{{$index}}.$error.max">Error</div>
</div>
Output
abc
Error
def
Error

What I fix
Use ng-form - HTML
Input type for "number" not "text" - HTML
Named input - HTML
Fix amount string to number - JS
As a comment, It may possible duplicate of How to validate inputs dynamically created using ng-repeat, ng-show (angular)
After you read that question and answers, you may understand my answer.
HTML Code
<ul ng-repeat="scholarship in scholarships">
<ng-form name="myForm">
{{scholarship.name}}
<input type="number" name="scholarshipName" id="sAmount-{{$index}}" max="500" ng-model="scholarship.amount" style="width:100px;" required integer />
<div class="alert error" ng-show="myForm.scholarshipName.$error.max">max error</div>
</ng-form>
</ul>
JS Code
var app = angular.module('myapp', [], function () {});
app.controller('AppController', function ($scope) {
$scope.scholarships = [
{
"name" : "abc",
"amount" : 456
},
{
"name" : "def",
"amount" : "789"
}
];
});

Related

Append key value pair to angularjs object

I am getting json output from laravel 5.2 form request validation
My json output is:
{
"title": [
"The title field is required."
],
"description": [
"The description field is required."
],
"address.city": [
"City field is required"
]
}
Appending this output to object
var self = this;
self.error = {
address: {}
};
var onFailure = function (response) {
angular.forEach(response.data, function(value, key) {
self.error[key] = value[0];
});
};
I want to access this error object to my view, for "address.city", I can't access it using "ctrl.error.address.city", rest I can access
How to append object with key containing "." and show it in view?
Here is what you need. But its better not to have (.) in a property name. Instead you can use a underscore(_). Avoid using dot(.) as a chaaracter in property names.
var myApp = angular.module('MyApp', []);
myApp.controller('MyCtrl', function ($scope) {
$scope.foo={};
$scope.foo['hello.There'] = "I'm foo!";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="MyApp" ng-controller="MyCtrl">
{{foo["hello.There"]}}<br />
<input type="text" ng-model="foo['hello.There']" />
</div>
if you know the key name then the only way you can access it is by [].
Check the fiddle for more info.
https://jsfiddle.net/9f4mbh1h/1/
You need to change your code to this
in your controller
myApp.controller('MyCtrl', function ($scope) {
$scope.foo={};
$scope.foo "hi";
});
in html
<div ng-app="MyApp" ng-controller="MyCtrl">
<input type="text" ng-model="foo" /> </div>

Selection on selectbox in IE when modifying the options with angular

I'm developping an application that use Angular and we want to synchronize two selectbox (HTML). It means when I click a value in the first selectbox , I want value in the second selectbox updated, and clickable too.
I did the following plunker to explain our problem:
http://plnkr.co/edit/KkBVcu29CZ6Elr741ZPe?p=preview
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js" type="text/javascript"></script>
<script>
'use strict';
angular.module("myApp", []).run(function($rootScope) {}).config(function () {});
angular.module('myApp').controller('myCtrl', function(
$scope) {
//$scope.obj2Selected = null;
$scope.list1 = [];
$scope.list1.push({
id : "1",
name : "1",
selected : false
});
$scope.list1.push({
id : "2",
name : "2",
selected : false
});
$scope.list1.push({
id : "3",
name : "3",
selected : false
});
$scope.list2 = [];
$scope.list2 .push({
id : "1",
name : "1"
});
$scope.list2.push({
id : "2",
name : "2"
});
$scope.list2.push({
id : "3",
name : "3"
});
$scope.selectionObjDone = function(){
$scope.obj2Selected = null;
$scope.list2.length = 0;
$scope.list2.push({
id : Math.random().toString(),
name : Math.random().toString()
});
$scope.list2.push({
id : Math.random().toString(),
name : Math.random().toString()
});
};
});
</script>
<div ng-controller="myCtrl">
<select size="10" id="listNodes" style="width:200px;"
ng-options="obj as obj.name for obj in list1 track by obj.id" ng-model="objSelected"
ng-change="selectionObjDone()">
</select>
<select size="10" style="width:200px;" id="select2"
ng-options="obj as obj.name for obj in list2 track by obj.id"
ng-model="obj2Selected" >
</select>
</div>
</html>
In this plunker everything looks fine. But if you copy/paste the exact same code in a test.html for example, opening it in IE (V11), you'll see the problem:
Start by clicking on the first selectbox to choose an option or another.
Try to select then an option in the second selectbox, you'll see that the selection is no more possible.
It works well in FF or Chrome, and also it works better on Plunker, even if sometimes it stops to work in Plunker (I did not find the exact use case).
It has a real link to the fact that I empty the array that is used to fill the 2nd selectbox. If I comment this line, everything work fine:
$scope.list2.length = 0;
I tried different ways to empty this array:
How do I empty an array in JavaScript?
Does anybody have an idea on what happens here and how to fix this?
Thanks
Finally, even with an expert of Angular we did not find the answer, but waiting a few, the new version of Angular (1.5.7) resolved by magic the problem!

Angular.JS data binding

I have started learning angular.js but I am kind of having trouble understanding the data binding and scopes.
Here is my Html file :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"> </script>
<title>Egghead</title>
</head>
<body data-ng-app="myApp">
1. <div>
NAME : <input type = "text" name = "name" data-ng-model="data.name"/>
Typed Name : <b>{{data.name}}</b>
<br><br>
EMAIL: <input type = "email" name = "email" data-ng-model="data.email"/>
Typed Email : <b>{{data.email}}</b>
</div>
2. <div data-ng-controller="firstController">
NAME : <input type = "text" name = "name" data-ng-model="data.name"/>
Typed Name : <b>{{data.name}}</b>
<br><br>
EMAIL: <input type = "email" name = "email" data-ng-model="data.email"/>
Typed Email : <b>{{data.email}}</b>
</div>
3. <div data-ng-controller="secondController">
NAME : <input type = "text" name = "name" data-ng-model="data.name"/>
Typed Name : <b>{{data.name}}</b>
<br><br>
EMAIL: <input type = "email" name = "email" data-ng-model="data.email"/>
Typed Email : <b>{{data.email}}</b>
</div>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
Now when I have this module for my current html :
(function(){
var myApp = angular.module('myApp', []);
myApp.controller('firstController', function($scope, $rootScope) {
/*$rootScope.data = {name : "root", email : "root#gmail.com"};
$scope.data = {name : "Ishan", email : "soni.ishan.nitj#gmail.com"};*/
});
myApp.controller('secondController', function($scope) {
/*$scope.data = {name : "Divyan", email : "soni.divyan#gmail.com"};*/
});
})();
any changes that I make in any of the textbox for say the "name" input reflects and is bound everywhere. Example I make a change in the input text with name = "name" inside the second controller, the value in the text box for first also changes, but when I remove the comments from my javascript file, any change I make in the second controller's input box are not reflected in the first's input box. Why?
$rootScope is parent of all scopes, so if you assign property to it, it will be available everywhere in views. Every controller has $scope, you have two sibling controllers, so they have different scopes, if you want to share data between controllers, you shall use service. Like this:
myApp.factory('dataSrvc', function () {
return {
getData: function () {
return {
name : "Divyan",
email : "soni.divyan#gmail.com"
};
}
};
});
Then inject it into controllers:
myApp.controller('firstController', function($scope, dataSrvc) {
scope.data = dataSrvc.getData();
});
myApp.controller('secondController', function($scope, dataSrvc) {
scope.data = dataSrvc.getData();
});
In this case changes in first controller will not reflect on second and vice versa, because getData returns new instance of object every time (with same data).

AngularJS (Filter) : How to implement multi-keyword search on object attributes?

Check this jsFiddle : http://jsfiddle.net/mystikacid/hajo0c33/
I'm using the keyword in the input box to filter the objects to be shown. This works fine as far as I enter only one keyword. But if I try to filter by two keywords (for two attributes, example, my query is - 'Transformers 150V' as I want to look for those Transformers which use 150V, it does not show any result.
HTML
<div ng-app="myApp">
<div ng-controller="myCtrl">
<input type='text' ng-model='query' placeholder = "Search" />
<div ng-repeat="product in products | filter : query">
{{product.name}} |
{{product.family}} |
{{product.amperage}} |
{{product.volt}}
</div>
</div>
Javascript
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope){
$scope.products = [
{
name : '9T21S1050',
family : 'Transformer',
amperage : '20A',
volt : '150V'
},
{
name : '9T85B3092',
family : 'Transformer',
amperage : '15A',
volt : '200V'
},
{
name : 'AEU3182RCXAXB4',
family : 'Panel Board',
amperage : '30A',
volt : '250V'
},
{
name : 'AQU1182RCXAXB4',
family : 'Panel Board',
amperage : '25A',
volt : '300V'
},
{
name : 'AQU1422RCXAXT1',
family : 'Panel Board',
amperage : '35A',
volt : '150V'
}
]
});
I understand that I need to write a function for the filter, but I've not been able to make it work so far. Let me know if you'd like to see the function too.
Thanks.
i am creating a new filter that will give product if both value will be present in it.
var m = angular.module('yourModuleName');
m.filter('advancefilter', ['$filter', function($filter){
return function(data, text){
var textArr = text.split(' ');
angular.forEach(textArr, function(test){
if(test){
data = $filter('filter')(data, test);
}
});
return data;
}
}]);

Can't bind inside ng-show that is in ng-repeat

So I am working on a small login form using AngularJS and it seemed extremely natural to remove duplicated code by using an ng-repeat directive. Everything is very natural and works well except any kind of binding inside ng-show, this is where things gets unintuitive and break down. A fiddle of the work so far can be found here.
What I am wondering is why does everything break down for ng-show? If I dump the ng-repeat and duplicate the code everything works fine for all three ng-show instances assuming that I manually type the references to the elements and values.
Below is a copy of the fiddle html and javascript:
<div ng-app='loginApp' ng-controller='loginController'>
<form name='loginForm' novalidate>
<div class='form-group' ng-repeat='field in fields'>
<label>{{field.label}}</label>
<input type='{{field.inputType}}' class='form-control' name='{{field.inputName}}' ng-minlength='{{field.minlength}}' ng-maxlength='{{field.maxlength}}' ng-model='field.value' ng-focus='inputFocused'/>
<!-- The ng-show below doesn't work as expected -->
<div ng-show="canShowUserMsgs(inputFocused, loginForm.{{field.inputName}}.$dirty, loginForm.{{field.inputName}}.$invalid)">
<!-- The ng-show below doesn't work as expected -->
<p ng-show="loginForm.{{field.inputName}}.$error.minlength" class='help-block'>Must be more than {{field.minlength}} characters long.</p>
<!-- The ng-show below doesn't work as expected -->
<p ng-show="loginForm.{{field.inputName}}.$error.maxlength" class='help-block'>Must be less than {{field.maxlength}} characters long.</p>
</div>
</div>
</form>
</div>
var loginApp = angular.module('loginApp', []);
loginApp.controller('loginController', function($scope, $http) {
$scope.fields = [
{
label : "User Name",
inputType : "text",
inputName : "userName",
value : "",
minlength : 5,
maxlength : 15
},
{
label : "Password",
inputType : "password",
inputName : "password",
value : "",
minlength : 5,
maxlength : 15
}
];
$scope.canShowUserMsgs = function(inputFocused, inputDirty, inputInvalid) {
return (inputDirty && inputInvalid && !inputFocused); };
});
loginApp.directive('ngFocus', [function() {
return {
restrict: 'A',
link: function(scope, element, attrs, ctrl) {
var modelName = attrs['ngFocus'];
scope[modelName] = false;
element.bind('focus', function(evt) {
scope.$apply(function() {scope[modelName] = true;});
}).bind('blur', function(evt) {
scope.$apply(function() {scope[modelName] = false;});
});
}
}
}]);
you have to add ng-form inside the ng-repeat and need to do some modifications to how you use the ng-show. Check the working sample of your code.
working copy
This doesn't work: <p ng-show="loginForm.{{field.inputName}}.$error.minlength" because the interpretation of the curly brace expression only happens once, there's not two passes: one to generate the bind path without any curly braces, then a second to evaluate the bind path against the scope. It's not like that. Everything happens in a single pass. So, convert it to a controller function call:
<p ng-show="minLength(field)"

Resources