Angular newbie: non-trivial form validation? - javascript

I am new to Angular, and I would like to do some non-trivial input validation.
Basically I have a table. Each row contains three text inputs. When the user types into any text inputs, I would like to check whether the table contains at least one row with three non-blank input fields. If it does, I want to show a message.
I have no idea how to do this cleanly in Angular, any help would be much appreciated.
This is my HTML:
<tr data-ng-repeat="i in [1,2,3,4,5]">
<td data-ng-repeat="i in [1,2,3]">
<input ng-model="choice.selected" ng-change='checkAnswer(choice)' type="text" />
</td>
</tr>
...
<div ng-show="haveCompleteRow">we have a complete row!</div>
And controller:
$scope.haveCompleteRow = false;
$scope.checkAnswer=function(choice){
$scope.haveCompleteRow = true; // what to do here?
}
Here is a plunker demonstrating the issue: http://plnkr.co/edit/Ws3DxRPFuuJskt8EUqBB

To be honest, I wouldn't call this form validation. But for starters, it would be a lot simpler if you had a real model to observer, instead of an array in the template. The way you started will, or at least could, lead you to dom-manipulation inside the controller, which is a no-go for angular.
A simple first sketch with a model could be:
app.controller('TestCtrl', ['$scope', function ($scope) {
$scope.rows = [
[{text: ''}, {text: ''}, {text: ''}],
[{text: ''}, {text: ''}, {text: ''}],
[{text: ''}, {text: ''}, {text: ''}]
];
$scope.haveCompleteRow = false;
// watch for changes in `rows` (deep, see last parameter `true`).
$scope.$watch('rows', function (rows) {
// and update `haveCompleteRow` accordingly
$scope.haveCompleteRow = rows.some(function (col) {
return col.every(function (cell) {
return cell.text.length > 0;
});
});
}, true);
}]);
with:
<body ng-controller="TestCtrl">
<table>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="row in rows">
<td data-ng-repeat="cell in row">
<input ng-model="cell.text" type="text" />
</td>
</tr>
</tbody>
</table>
<div ng-show="haveCompleteRow">we have a complete row!</div>
</body>
as the template.
Demo: http://jsbin.com/URaconiX/2/

Related

Show /hide warning messag based on filtered outputs ng-repeat

Please find the attached fiddle where I want to post a warning mesaage "No data to display" if the filter fais to match any results in the button clicks.
Fiddle ng-repeat filter
I have given condition for both table and message so that they should be displayed as and when the clicks happen.
<div ng-show="name===null">No results</div>
The above message should be displayed if there are no satisfying data in the table based on link clicks,together the table should be hidden.
I tried to give conditions based on property name but its not working.
Check your fiddle http://jsfiddle.net/w0L4o8jm/6/
By default I am making filter with Fruit. You can change it in the controller.
Coming to the answer, Calculate the filtered items length according to the filter. If length 0 or name '', then show no results. Otherwise show results in the table. Just copy paste the below code in your fiddle and check it out.
<html ng-app="app">
<a ng-click="name = 'Fruit'">Fruit</a>
<a ng-click="name = 'Nut'">Nut</a>
<a ng-click="name = 'Seed'">Seed</a>
<body ng-controller="main">
<a ng-click="name = ''">clear filter</a>
<br> <br> <br>
<div ng-show="(name=='' || !filtered.length)">No results</div>
<div ng-repeat="link in filtered = (links|filter:name)"></div>
<table class="table" ng-show="(filtered.length != 0 && name!='')">
<thead>
<tr>
<th>Target</th>
<th>Level</th>
<tr>
<tbody>
<tr ng-repeat="link in links|filter:name">
<td>
{{link.name}}
</td>
<td>
{{link.category}}
</td>
</tr>
</tbody>
</table>
</body>
Controller code
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.filters = { };
$scope.name='Fruit';
$scope.links = [
{name: 'Apple', category: 'Fruit'},
{name: 'Pear', category: 'Fruit'},
{name: 'Almond', category: 'Nut'},
{name: 'Mango', category: 'Fruit'},
{name: 'Cashew', category: 'Nut'}
];
});
For Angular prior to 1.3
Assign the results to a new variable (e.g. filtered) and access it:
<div ng-repeat="link in filtered = (links|filter:name)"></div>
For Angular 1.3+
Use an alias expression (Docs: Angular 1.3.0: ngRepeat, scroll down to the Arguments section):
<div ng-repeat="link in links|filter:name as filtered"></div>
Try to use this code
Demo
<body ng-app="app" ng-controller="main">
<a ng-click="name = 'Fruit'">Fruit</a>
<a ng-click="name = 'Nut'">Nut</a>
<a ng-click="name = 'Seed'">Seed</a>
<a ng-click="name = ''">clear filter</a>
<br> <br> <br>
<div ng-show="name ==''">No results</div>
<table class="table" ng-show="name!=''">
<thead>
<tr>
<th>Target</th>
<th>Level</th>
<tr>
<tbody>
<tr ng-repeat="link in links | filter:name">
<td>
{{link.name}}
</td>
<td>
{{link.category}}
</td>
</tr>
</tbody>
</table>
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.filters = { };
$scope.name = '';
$scope.links = [
{name: 'Apple', category: 'Fruit'},
{name: 'Pear', category: 'Fruit'},
{name: 'Almond', category: 'Nut'},
{name: 'Mango', category: 'Fruit'},
{name: 'Cashew', category: 'Nut'}
];
});
Here you go! Updated fiddle
You had a few issues in there:
your ng-controller was on a div but you were setting name outside controller
<div ng-show="name===null">No results</div> Here you were comparing name with null but you were setting it to empty string in clear filter
Hope it helps!
Edit: On clear filter it was not showing all the items. Fixed and updated fiddle

ng-options result in two separate divs

I have a select using ng-options to serve up results. I can get it produce one of the json elements to a div, but i cannot seem to get it to do it for another. What am I missing?
HTML Code:
<table class="table">
<tr>
<td class="select_container">
<select class="form-control" ng-model="selectedOption_1" ng-options="select_array.value as select_array.displayName for select_array in select_array"></select>
</td>
<td colspan="2">{{selectedOption_1}}</td>
<td colspan="3">{{selectedOption_1}}</td>
</tr>
</table>
Angular Code:
$scope.select_array = [
{value: '1', region:'London', displayName: 'display_1'},
{value: '2', region:'London', displayName: 'display_2'},
{value: '3', region:'London', displayName: 'display_3'},
];
$scope.selectedOption_1 = '123,285';
So what I would like to have happen, is when you select an option, have it populate value in the first div, and region in the second. And have that data change based on which option you select. Thank you in advance for any advice.
Try this, You will to have map your entire object as a value of an option.
<table class="table">
<tr>
<td class="select_container">
<select class="form-control" ng-model="selectedOption_1" ng-options="select_array as select_array.displayName for select_array in select_array"></select>
</td>
<td colspan="2">{{selectedOption_1.value}}</td>
<td colspan="3">{{selectedOption_1.region}}</td>
</tr>
</table>

Href not working within Javascript function

I have got this code below and I want to know how I can add a clickable link to the boxes under each title.
I want this Call on Skype to appear in the first box. But I cannot get it to work as the whole function just stops working when I add it.
function MyCtrl($scope) {
$scope.environment_service_packages =
[
{name: 'obj1', info: {text: '<?php echo "A html link below \\n\\n Call on Skype"; ?>', show: true}},
{name: 'obj2', info: {text: 'some extra info for obj2', show: true}},
{name: 'obj3', info: {text: 'some extra info for obj3', show: true}},
{name: 'obj4', info: {text: 'some extra info for obj4', show: false}},
];
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app>
<table ng-controller="MyCtrl" class="table table-hover table-striped">
<tr class="info">
<td>...</td>
</tr>
<tbody ng-repeat="x in environment_service_packages">
<tr ng-click="x.info.show = !x.info.show">
<td> {{ x.name }}
</tr>
<tr ng-show="x.info.show">
<td>
<pre>{{ x.info.text }}</pre>
</td>
</tr>
</tbody>
</table>
</body>
Putting ng-repeat on the tbody will create a body for every member in the array.
Try putting ng-repeat-start on the first row and ng-repeat-end on the second row.
You can't run PHP code in client side...
you need to change HTML to something like:
Call on Skype

Populate HTML table with search value Angular

I have a json file, that will eventually be called from a server with an API. Currently am just calling from an object.
I am creating an HTML file with a table navigation, where each header element also has a search box and submit button.
I would like the table to be blank on start, and when one of the header values is searched (id, nickname, email, etc), the json value that contains at least part of that search will populate the table.
I am new to the Angular syntax and am trying to get an idea of how this would even work.
(function() {
var app = angular.module('tool', []);
app.controller('searchController', function() {
this.info = data.people;
this.findId = function(idInput) {
angular.forEach(that.id, function(value, key) {
if (value.contains(idInput)) {
// not sure what to put here.
}
});
};
});
var data = {
"people": [{
"id": "2245231",
"nickname": "heyyman",
"email": "info#gmail.net",
"lastIp": "127.0.0.1",
"regIp": "127.0.0.1",
}, {
"id": "2245232",
"nickname": "heyyman2",
"email": "info2#gmail.net",
"lastIp": "127.0.0.2",
"regIp": "127.0.0.2",
}
};
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<main>
<table ng-controller="searchController as search">
<thead>
<tr id="tableNavigation">
<td></td>
<td>ID
<input type="text" ng-model="idInput">
<input type="submit" ng-click="findId(idInput)">
</td>
<td>Nickname</td>
<td>Login / Email</td>
<td>Last IP</td>
<td>Registration IP</td>
</tr>
</thead>
<tbody id="tableCanvas">
<tr ng-repeat="people in search.info" ng-class-even="'even'">
<td></td>
<td>{{people.id}}</td>
<td>{{people.nickname}}</td>
<td>{{people.email}}</td>
<td>{{people.lastIp}}</td>
<td>{{people.regIp}}</td>
</tr>
</tbody>
</table>
</main>
So far, this is what I've done. Also, I've linked a JSFiddle.
http://jsfiddle.net/ho00cLkk/
Please let me know if what I am asking is confusing or not clear.
It seems to me that your question consists of two separate parts:
How do I filter the displayed items?
How do I hide all results until the first search is made?
As the second question seems uninteresting to me (many possible solutions, no general problem), I'll focus on the first one. You might want to read the documentation: https://docs.angularjs.org/api/ng/filter/filter . Then it's pretty simple and you don't even need any submit buttons:
<table>
<thead>
<tr>
<th>
Name
<input type="text" ng-model="searchProps.name">
</th>
...
</tr>
</thead>
<tbody>
<tr ng-repeat="person in people | filter:searchProps">
...
</tr>
</tbody>
</table>
(where people is your search.info). Table rows will be automatically filtered to contain only the items with properties partially matching the values in searchProps.
CodePen example: http://codepen.io/anon/pen/jEEZaa

jsfidle filter not working in angularjs

Here is the jsfiddle, i can get it to work with true, false values, but when i try to filter by name, it doesn't work any suggestions ?
jsFiddle
<div ng-controller="MyCtrl">
<button class="btn" ng-click='filterCriteria={}'>All</button>
<button class="btn" ng-click='filterCriteria.read=true'>Read</button>
<button class="btn" ng-click='filterCriteria.title={{messages[0].title}}'>Foo</button>
<pre>{{messages[0].title}}</pre>
<hr/>
<table class="table table-bordered">
<thead>
<tr>
<td><strong>Title</strong></td>
<td><strong>Content</strong></td>
<td><strong>Read</strong></td>
</tr>
</thead>
<tbody>
<tr ng-repeat='message in messages |filter:filterCriteria'>
<td>{{message.title}}</td>
<td>{{message.content}}</td>
<td>{{message.read}}</td>
</tr>
</tbody>
</table>
</div>
function MyCtrl($scope) {
$scope.filterCriteria = {};
$scope.messages = [{
title: 'Foo',
content: 'Foo content',
read: false},
{
title: 'Bar',
content: 'Bar content',
read: true}
];
}
Since your filterCriteria is not cleared you are facing the issue.
Fiddle
Try the below for filtering by name:
$scope.filterByName= function(name){
$scope.filterCriteria={},
$scope.filterCriteria.title=name;
}
NOTE: I assume you are asking about new filtering when button is clicked and old filters are to be removed.
I think you don't need to use {{}} in ng-click
use ()
try
<button class="btn" ng-click='filterCriteria.title=(messages[0].title)'>Foo</button>
http://jsfiddle.net/JtAZM/43/
Just leave out the brackets:
<button class="btn" ng-click='filterCriteria.title=messages[0].title'>Foo</button>
Works here

Categories

Resources