What's the meaning of sortBy in ng-click? - javascript

I'm pretty new in AgularJS, and when I tried to do the practice:
JS file:
function CustomersController() {
this.sortBy = 'name';
this.reverse = false;
this.customers= [{joined: '2000-12-02', name:'John', city:'Chandler', orderTotal: 9.9956}, {joined: '1965-01-25',name:'Zed', city:'Las Vegas', orderTotal: 19.99},{joined: '1944-06-15',name:'Tina', city:'New York', orderTotal:44.99}, {joined: '1995-03-28',name:'Dave', city:'Seattle', orderTotal:101.50}];
this.doSort = function(propName) {
this.sortBy = propName;
this.reverse = !this.reverse;
};
}
HTML file:
<!doctype html>
<html ng-app="customersApp">
<head>
<title>Iterating Over Data</title>
<link href="styles.css" rel="stylesheet" type="text/css" />
</head>
<body ng-controller="CustomersController">
<h2>Customers</h2>
Filter: <input type="text" ng-model="customerFilter.name" />
<br /><br />
<table>
<tr>
<th ng-click="doSort('name')">Name</th>
<th ng-click="doSort('city')">City</th>
<th ng-click="doSort('orderTotal')">Order Total</th>
<th ng-click="doSort('joined')">Joined</th>
</tr>
<tr ng-repeat="cust in customers | filter:customerFilter | orderBy:sortBy:reverse">
<td>{{ cust.name }}</td>
<td>{{ cust.city }}</td>
<td>{{ cust.orderTotal | currency }}</td>
<td>{{ cust.joined | date }}</td>
</tr>
</table>
<br />
<span>Total customers: {{ customers.length }}</span>
<script src="angular.js"></script>
<script src="app/app.js"></script>
<script src="app/controllers/customersController.js"></script>
</body>
</html>
On the webpage I can click the table's head and sort by name. So I want to know that what's the meaning of sortBy ? Is it a built-in variable in $scope? I tried to change its name (like "sortby") and it doesn't sort (just reverse). If it is, where could I find the built-in functions of $scope? Thanks a lot!

First of all sortBy is just the name of the variable and is not built into the $scope. You could use anything. Notice that sortBy is referenced in 2 places:
In the HTML:
<tr ng-repeat="cust in customers | filter:customerFilter | orderBy:sortBy:reverse">
And in your controller in 2 places:
// This initializes the sort order
this.sortBy = 'name';
// This sets the new sort order when a user clicks on the table heding
this.sortBy = propName;
You are free to use another name for sortBy, you just need to replace it in all of those places.
However, orderBy is specific to the ng-repeat, so you can't change that name. For more information you can check out the last example on this page:
https://docs.angularjs.org/api/ng/directive/ngRepeat

Related

Get values of dynamically named inputs in Angular

In my fees-list.component.html template, I have something like the following:
<div class="container">
<div class="row" *ngFor="let meta of fees">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Amount owing (AUD)</th>
<th>Fee type</th>
<th>Title</th>
<th>Amount to pay (AUD)</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let fee of meta.fee">
<td>{{ fee.balance }}</td>
<td>{{ fee.type.desc }}</td>
<td>{{ fee.title }}</td>
<td><input id="{{ fee.id }}" type="text" name="toPay" value="{{ fee.balance }}"></td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<div class="col-md-4"><strong>Total to pay: </strong><input type="text" name="total" value="{{ meta.total_sum }}"> </div>
</div>
</div>
</div>
The requirement for my interface is twofold. If users change the value of an individual fee (fee.balance), the value in the total text input field should be updated.
Secondly, if the total input field is updated, I need to update the value(s) in the individual fees accordingly (reducing those by the appropriate amount from oldest fee to newest fee).
My question is, how do I do binding for these input fields which are dynamically generated, though they do have unique ids (id="{{ fee.id }})? I cannot work out how to target an individual fee field in my typescript file.
Use two way binding with ngModel
<input [name]="fee.id" type="text" [(ngModel)]="fee.balance">
Now when the user types in the textbox it will update the value in the array directly.
Also you should not be using {{}} binding on your attributes like that, use attribute binding with the [box] syntax.
<input type="text" name="total" [value]="total_sum">
You can calculate the total in your TypeScript like
get total_sum() {
return meta.fees.reduce((total, fee) => total + fee.balance, 0);
}
One approach ( preferred) is to create the controls dynamically.
your typescript file :
constructor(){
this.formGroup = new FormGroup();
const controls = meta.fee.map((fee)=>{
this.formGroup.addControl(fee.id, new FormControl(fee.balance))
});
// now you have a formGroup with all the controls and their value are initialized, you just need to use it in your template
}
your template :
<tbody>
<tr *ngFor="let fee of meta.fee">
<td>{{ fee.balance }}</td>
<td>{{ fee.type.desc }}</td>
<td>{{ fee.title }}</td>
<td><input id="{{ fee.id }}" [formControl]="formGroup.get(fee.id)" type="text" name="toPay"></td>
</tr>
</tbody>
So obviously, after this, you have the full power to do anything, for example, if you want to update a specific one of them:
updateValue(){
this.formGroup.get('oneOfThoseFeeIds').setValue('new value')
}
NOTE :
I haven't done Angular for a while and don't remember the exact syntaxes, but I hope this gives you a path
Can't you just use a service for that? I guess this is a way to go here, since you should try keeping your components as small as possible and communicate them by services.
Please, have a look at this chapter in angular documentation: https://angular.io/tutorial/toh-pt4

Angularjs data table dissappearing while rendering multiple times

I am using angular data table where i am generating table every time user selects an option.For the first input the data table render successfully but after that when user select onther option the data table disappear from the view.The problem can be solved if i place the data table options vm.dtOptions and vm.dtColumnDefs outside the function.But i need to solve the issue keeping the options inside the function as my $scope.ln is dynamically generated inside the function and i need this value to limit the loop.So how can i achieve my goal so that instead of disappearing multiple table can be showed based on user input?
var app = angular.module('myApp',['datatables']);
app.controller('MyCtrl', function($scope,DTOptionsBuilder,DTColumnBuilder,DTColumnDefBuilder) {
$scope.department = [
{value : "1", name : "sales"},
{value : "2", name : "admin"},
{value : "3", name : "other"}
];
$scope.dep=$scope.selected_dep;
$scope.depshow=function(){
$scope.dep=$scope.selected_dep;
if($scope.dep==1)
{
$scope.list = [
{"eid":"10","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"20","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"30","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"}
];
}
else if($scope.dep==2)
{
$scope.list = [
{"eid":"40","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"50","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"60","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"}
];
}
if($scope.dep==3) {
$scope.list = [
{"eid":"70","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"80","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"},
{"eid":"0","dyn1":"dval1","dyn2":"dval2","dyn3":"dval3","sales":"20"}
];
}
$scope.vm = {};
$scope.vm.dtOptions = DTOptionsBuilder.newOptions()
.withOption('order', [0, 'asc']);
$scope.ln=4;
$scope.vm.dtColumnDefs = [
];
for(var i=1;i<$scope.ln;i++){
$scope.vm.dtColumnDefs.push(DTColumnDefBuilder.newColumnDef(i).notSortable());
}
}
});
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://phpflow.com/demo/angular_datatable_demo/angular-datatables.min.js"></script>
<script src="https://phpflow.com/demo/angular_datatable_demo/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://phpflow.com/demo/angular_datatable_demo/datatables.bootstrap.css">
</head>
<div class="container">
<div ng-app="myApp" ng-controller="MyCtrl">
Select <select ng-model="selected_dep" ng-change="depshow()" ng-options="item.value as item.name for item in department">
<option value="">select a department</option>
</select>
{{selected_dep}}
<table class="table table-striped table-bordered" dt-options="vm.dtOptions" dt-column-defs="vm.dtColumnDefs" datatable="ng">
<thead>
<tr>
<th>Employee ID</th>
<th>dynamic clm1</th>
<th>dynamic clm2</th>
<th>dynamic clm3</th>
<th>sales</th>
</thead>
<tbody>
<tr ng-repeat="data in list">
<td> {{ data.eid }} </td>
<td> {{ data.dyn1 }} </td>
<td> {{ data.dyn2 }} </td>
<td> {{ data.dyn3 }} </td>
<td> {{ data.sales }} </td>
</tr>
</tbody>
</table>
</div>
The reason for this is that you dont have brackets on the
else if($scope.dep==2)

After redirecting to another page how to use controller and scope data of previous page in angularjs

This is for an assignment. Here table contains book details which contains book name, author, price, ISBN and category. When user click on book name it should redirect to order page displaying book name, author and price.
BookPage.html
<script type="text/javascript" src="book.js">
<body ng-app="mymodule" >
<div ng-controller="myController" >
<table border=2>
<thead>
<tr>
<th>ISBN</th>
<th>NAME</th>
<th>AUTHOR</th>
<th>CATEGORY</th>
<th>PRICE</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="book in books">
<td>{{ book.ISBN }}</td>
<td >{{ book.Name }}</td>
<td>{{ book.Author }}</td>
<td>{{ book.Category }}</td>
<td>{{ book.price }}</td>
</tr>
</tbody>
</table>
**books.js**
var myapp = angular.module('mymodule', []);
myapp.controller("myController", function($scope, $http,$window) {
$http.get("https://api.myjson.com/bins/p4ujn").then(function(response) {
$scope.books = response.data;
$scope.getdetail=function(){
$scope.getbookdetail=this.book;
$window.location.href = "orderpage.html";
}
});
});
Page to be redirected when user click on book name.
orderpage.html
<script type="text/javascript" src="book.js"></script>
<body ng-app="mymodule" >
<div ng-controller="myController" >
{{getbookdetail.Name}}<br>
{{getbookdetail.Author}}
{{getbookdetail.price }}<br>
</div>
</body
This is my code. It display nothing, just a blank page.
You can use a Service or factory to share the data across the controllers.
DEMO
var app = angular.module("clientApp", [])
app.controller("TestCtrl",
function($scope,names) {
$scope.names =[];
$scope.save= function(){
names.add($scope.name);
}
$scope.getnames = function(){
$scope.names = names.get();
}
}
);
app.factory('names', function(){
var names = {};
names.list = [];
names.add = function(message){
names.list.push({message});
};
names.get = function(){
return names.list;
};
return names;
});
<!doctype html>
<html >
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="clientApp">
<div ng-controller="TestCtrl">
<input type="text" ng-model="name">
<button ng-click="save()" > save</button>
</div>
<div ng-init="getnames()" ng-controller="TestCtrl">
<div ng-repeat="name in names">
{{name}}
</div>
</div>
</body>
</html>
Apart from service/factory , you can go for other options like localStorage and rootScope, but those are not recommended ways.
You should use factory/Services, localStorage, routeParams or Child Parent controllers

AngularJS on ng-dblclick change input[text]

I have a table that is populated with ngRepeat and I have a input[text] where you can filter the table.
This works fine but now I came up with the idea to have the possibility to double-click on an element in the table and add the text to the search input[text] so the filter is applied straight when you double-click on the text.
Unfortunately it does not work as expected.
I have done this:
<input type="text" placeholder="Search..." data-ng-model="userinput" />
<p data-ng-dblclick="userinput='query'">Double click to use query to search</p>
And in the ngRepeat I use the ng-model "userinput" to filter but the value of the text input is not changing.
I also tried to specify the model "userinput" as variable in the controller and then change it per function but it is not working.
Is there something I'm missing?
Normally I would change the variable in the controller and it should automatically change the text input since it uses this variable as model. Then with this it should change the filter too but nothing happens.
WORKING
Code ngRepeat
<tr data-ng-repeat="dat in data | filter: userInput | filter: tsSelect | filter: advSelect | filter: checkedFilter | orderBy: ['client', 'ssrstatus'] | limitTo: totalDisplay" id="{{ dat.bannerid }}"> <!-- | unique: 'bannerid' | filter: errorSelect| -->
<td>
<input type="checkbox" id="checked" data-ng-model="dat.checked" data-ng-change="updateCheckedStatus(dat._id['$id'], dat.checked)">
<label for="checked">Checked</label>
</td>
<td data-ng-dblclick="search(dat.clientid)">{{ dat.clientid }}</td>
<td data-ng-dblclick="search(dat.client)" class="txtleft">{{ dat.client }}</td>
<td data-ng-dblclick="search(dat.tsengineer)">{{ dat.tsengineer }}</td>
<td data-ng-dblclick="search(dat.bannerid)">{{ dat.bannerid }}</td>
<td data-ng-dblclick="search(dat.bannertype)" class="txtleft">{{ dat.bannertype }}</td>
<td data-ng-dblclick="search(dat.width + 'x' + dat.height)">{{ dat.width == 0 ? 0 : dat.width - 50 }}x{{ dat.height == 0 ? 0 : dat.height - 50 }}</td>
<td data-ng-dblclick="search(dat.ssrstatus)" class="txtleft">{{ dat.ssrstatus }}</td>
<td data-ng-dblclick="search(dat.datebegin)">{{ dat.datebegin }}</td>
<td data-ng-dblclick="search(dat.dateupdated)">{{ dat.dateupdated }}</td>
<td>
<button class="preview {{ dat.bannerid }}" data-ng-click="showPreview(dat.bannerid, dat.clicktotestbanner, dat.width, dat.height)"></button>
</td>
<!-- <td id="{{ dat.bannerid }}" class="banner-preview"></td> -->
Controller
$scope.userInput = "";
$scope.search = function(query){
$scope.userInput = query;
}
I think it's because of your userinput='query' evaluated inside ng-repeat.
Let's name your outer scope "scopeA". The ng-model="userinput" of the search input would be referencing scopeA.userinput.
As we know, a new scope is created for every ng-repeat items. If you run userinput='query' in one of these scopes (name it scopeB), you would be assigning 'query' to scopeB.userinput instead of scopeA.userinput.
In this situation, scopeB is likely to be a child of scopeA. If you use angular-batarang Chrome extension to have a look at the scope tree, you would find both scopes to have userinput field.
One solution would be to use a function to assigning value to userinput instead of ng-dblclick expression. Like:
<p data-ng-dblclick="setUserinput('query')">Double click to use query to search</p>
And add a function setUserinput to your scope:
$scope.setUserinput = function(newValue) {
$scope.userinput = newValue;
}

Spring: convert from JSTL(forEach) to angular.js(ng-repeat)

I am new to angular.js, I have a spring MVC application and I will like to switch from jstl to angular.js, I started this way
<table>
<c:forEach var="list" items="${list}">
<tr class="alt" ><td >${list.name}</td><td >${list.value}</td> </tr>
</c:forEach>
</table>
to
<table ng-app="" id="users">
<tr ng-repeat="x in list">
<td>{{ x.name }}</td>
<td>{{ x.value }}</td>
</tr>
</table>
If you really want to write the information directly in HTML you can add a tag with the required script.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
angular.module('AppNameHere', [])
.controller('exampleController', function() {
this.list = [{
name: 'Fool',
value: '12'
},
{
name: 'Bar',
value: '15'
}];
});
</script>
</head>
<body ng-app="AppNameHere">
<table id="users" ng-controller="exampleController as example">
<tr ng-repeat="x in example.list">
<td>{{ x.name }}</td>
<td>{{ x.value }}</td>
</tr>
</table>
</body>
</html>
But, as #Vaelyr said, AngularJS is commonly used to fetch data from server (using ajax or something similar) and show the results on the page:
// By default, you can use only 1 module per page.
angular.module('AppNameHere', [])
// service to load the data from server
.factory('exampleFactory', function($q){
var deferred = $q.defer();
// TODO: Load async...
var list =
[{
name: 'Fool',
value: '12'
},
{
name: 'Bar',
value: '15'
}];
deferred.resolve(list);
return deferred.promise;
})
// controller to show the data on the page
.controller('exampleController', function(exampleFactory) {
var controller = this;
controller.list = [];
// When the data is fetched from the server...
exampleFactory.then(function(list) {
// bind to the page
controller.list = list;
});
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-app="AppNameHere">
<table id="users" ng-controller="exampleController as example">
<tr ng-repeat="x in example.list">
<td>{{ x.name }}</td>
<td>{{ x.value }}</td>
</tr>
</table>
</body>
</html>

Categories

Resources