How to get the function result in ng-repeat in AngularJS? - angularjs

In ng-repeat trying to display the location address by passing the latitude and longitude to a function as shown below:
$scope.address = function(lat,lng){
return reverseGeocode.geocodePosition(lat,lng, function(address){
console.log(address);
return address;
});
};
I am using reverseGeocode.geocodePosition to fetch the address and below is my view
<table class="rideTable">
<tbody>
<tr class="" ng-repeat="item in rideDetailsArray">
<td class="ridTd">
<div class="rideName">Ride {{$index + 1}}</div>
</td>
<td>
<p>Pick location : {{address(item.pick_lat,item.pick_long)}}</p>
<p>Drop location : {{address(item.drop_lat,item.drop_long)}}</p>
</td>
</tr>
</tbody>
</table>
Pick location and drop location is not displaying in the view. How can i fix this and can i get any help.

try this call function from ng-repeat
$scope.LocationNameFilter = function (id)//here pass your object id
{
if ($scope.GetLocation.length > 0) {
var SelectStream = [];
if (id) {
SelectStream = $filter('filter')($scope.GetLocation,
{ _id: id }); //some condition passing your values
}
return SelectStream[0].AddressName;
}
else {
}
};

You need to return the response as well, Change your function as
$scope.address = function(lat,lng){
return reverseGeocode.geocodePosition(lat,lng, function(address){
console.log(address);
return address;
});
};

$scope.address is a function which doesn't return anything. So, by default, the return value is undefined.
Thus, AngularJS displays it as blank in the view. You may want to change the function as below:
$scope.address = function(lat,lng){
return reverseGeocode.geocodePosition(lat,lng, function(address){
console.log(address);
return address;
});
};

Related

Generated password using angular js not working

I want to make the password is auto generated and to pass it to the controller :
this is my view.jsp:
<tr>
<td class="leftDetails">Password</td>
<td class="rightDetails"><input type="text" name="password" ng-model="newUser.password" ng-disabled="isEditMode" id="p"/></td>
<td class="rightDetails"><input type='button' value ='generate' onclick='document.getElementById("p").value = Password.generate(16)' ng-show="add"></td>
<td class="leftDetails"></td>
<td class="rightDetails"></td>
</tr>
<script>
var Password = {
_pattern : /[a-zA-Z0-9_\-\+\.]/,
_getRandomByte : function()
{
if(window.crypto && window.crypto.getRandomValues)
{
var result = new Uint8Array(1);
window.crypto.getRandomValues(result);
return result[0];
}
else if(window.msCrypto && window.msCrypto.getRandomValues)
{
var result = new Uint8Array(1);
window.msCrypto.getRandomValues(result);
return result[0];
}
else
{
return Math.floor(Math.random() * 256);
}
},
generate : function(length)
{
return Array.apply(null, {'length': length})
.map(function()
{
var result;
while(true)
{
result = String.fromCharCode(this._getRandomByte());
if(this._pattern.test(result))
{
return result;
}
}
}, this)
.join('');
}
};
My problem is want to pass the generated password to my controller ,it was empty
How to correct that. thanks in advance?
The angular way to solve this issue is to update your input ng-model instead of selecting the element (Jquery way).
Instead of onClick use ng-click="newUser.password = Password.generate(16)"

How to use ng-click value as ng-repeat property?

How to get $scope.clickedVal in r.clickedVal?
Button click calls a function, passing in two parameters:
<a ng-click="display('Info', 'Admission_Info'); filters.Admission_Info= '!!'; ">Info</a>
<a ng-click="display('Info', 'SomeOther_Info'); filters.SomeOther_Info= '!!'; ">Other</a>
Function in the controller:
$scope.display = function (col, val) {
$scope.filters = {};
$scope.clickedColumn = col;
$scope.clickedVal = val;
};
Table displays a filtered view with 2 columns.
<tr ng-repeat="r in response | filter:filters as filtered " ng-show="filtered.length">
<td>{{ r.Name }}</td>
<td>{{ r.clickedVal }}</td>
</tr>
{{ r.{{clickedVal}} }} didn't work.
So for example, if the first button is clicked, r.clickedVal should return r.SomeOther_Info.
I've tried creating a filter as well but run into the same issue - m.value is incorrect.
SchoolProgramsApp.filter('myFilter', function () {
return function (input, column, value) {
var out = [];
angular.forEach(input, function (m) {
if (m.value === value) {
out.push(m)
}
})
return out;
}
});
You should use bracket notation to access property of the object by variable name:
{{ r[clickedVal] }}

Inconsistent Data on multiple page printing on a printer

Requirement
To print three(depends on the server response size) pages of print on one button click event.
Stored a barcode image an array, and loop through that array and bind the value to ctrl.barCodeImage. Then call the print service to print each bar code in different page. But it print always three same value that is the last value in the array.
It is a three separate pages with different bar code data in it.
This is the expected response
print 1
print 2
print 3
Current response is inconsistent.
It will come all pages same value , which is the last value in that array.
Implementation Details:
Created an DOM, which will be printed each time with different value assigned to it.
<div id="printThisElement" class="onlyprint" >
<table>
<tr>
<td>{{ ctrl.instCode }}</td>
<td align="center">{{ ctrl.date | dateDisplayFilter}} </td>
</tr>
<tr>
<td colspan="2" align="center"> <img ng-src="data:image/JPEG;base64,{{ctrl.barCodeImage}}"> </td>
</tr>
<tr>
<td colspan="2" align="center">{{ ctrl.user.name }} </td>
</tr>
<tr>
<td >Reg Id: {{ ctrl.regIdLookup }}</td>
<td align="center">{{ ctrl.testName }}</td>
</tr>
</table>
</div>
The print function which is getting called on the button click, added timeout to get assigned all the values on the print div.
vm.print = function() {
var res = [];
var sampleId = [];
var noTest = false;
angular.forEach(vm.gridOptions.data, function(item) {
if (item.sample != null) {
sampleId.push(angular.copy(item.sample.sampleId));
}
})
if(sampleId != null){
UserService.getInstitute(vm.user.instCode).then(function(response) {
vm.instCode = response.data.result.estName;
});
var userServicePromise = UserService.printBarCodes(sampleId);
userServicePromise.then(function(response) {
if (response != null && response.data != null && response.data.result != null) {
response.data.result.forEach(function(entry) {
vm.barCodeImage = angular.copy(entry);
$timeout(function() {
PrintService.printElement("printThisElement");
}, 0);
});
} else {
toaster.error(response.data.message);
}
});
}
}
}
Print Service, which is used to print the DOM.
(function() {
'use strict';
angular.module('app.services')
.factory('PrintService', PrintService);
PrintService.$inject = [];
function PrintService() {
var service = {
printElement: printElement
};
return service;
function printElement(elem) {
var printSection = document.getElementById('printSection');
// if there is no printing section, create one
if (!printSection) {
printSection = document.createElement('div');
printSection.id = 'printSection';
document.body.appendChild(printSection);
}
var elemToPrint = document.getElementById(elem);
// clones the element you want to print
var domClone = elemToPrint.cloneNode(true);
printSection.innerHTML = '';
printSection.appendChild(domClone);
window.print();
window.onafterprint = function() {
printSection.innerHTML = '';
}
};
}
})();
Not able to figure out why it gives inconsistent print data on each time. I guess it might be synchronous issue.
But most of the time it displays the last data in all three page of print.Thanks in advance.
Plunk here https://plnkr.co/edit/jwoC0bNQJ9J92l5S8ZJJ?p=preview
Any HELP ?
I forked your plunker and I use a queue to allow multiple printing
https://plnkr.co/edit/xZpcx6rCAUo9SemUPTt5?p=preview
I have a print function
function print(data) {
var domClone = '<div id="printThisElement" class="onlyprint" >'+
'<table>'+
'<tr> '+
'<td>{{ data.instCode }}</td>'+
'<td align="center">{{ data.date}} </td>'+
'</tr>'+
'<tr> '+
'<td colspan="2" align="center"> <img ng-src="data:image/JPEG;base64,{{data.barCodeImage}}"> </td>'+
'</tr>'+
'<tr> '+
'<td colspan="2" align="center">{{ ctrl.user.name }} </td>'+
'</tr>'+
'<tr> '+
'<td >Reg Id: {{ data.regIdLookup }}</td>'+
'<td align="center">{{ data.testName }}</td>'+
'</tr>'+
'</table>'+
'</div>'
printSection.innerHTML = '';
var scope = $rootScope.$new();
scope.data = data;
var domTemp = $compile(domClone)(scope)[0];
printSection.appendChild(domTemp);
$timeout(function(){
onPrintFinished(window.print());
}, 0);
}
And in PrintElement function i put in queu if printing is in progress :
if(!printInProgress) {
printInProgress = true;
print(data)
}
else {
queue.push(data);
}
At the end of printing run new printing with new data:
function onPrintFinished (printed){
var next = queue.shift();
if(next) {
console.log(next, queue);
$timeout(function() {
print(next);
});
}
else {
printInProgress = false;
}
}
I hope this time you have that you want
The problem is that vm.barCodeImage is set before corresponding PrintService.printElement is actually executed. So the sequence is:
vm.barCodeImage = angular.copy(first entry);
vm.barCodeImage = angular.copy(second entry);
vm.barCodeImage = angular.copy(third entry);
PrintService.printElement("printThisElement");
PrintService.printElement("printThisElement");
PrintService.printElement("printThisElement");
The solution is to modify your code in the following way:
$timeout(function() {
vm.barCodeImage = angular.copy(entry);
PrintService.printElement("printThisElement");
}, 0);
Thanks to that each call PrintService.printElement will use proper data and not the last element in the array.

Refreshing ng-repeat without $scope, without new request to sever

I have a table with this content:
<tbody>
<tr ng-repeat="result in ctrl.result track by $index">
<td ng-bind="$index+1"></td>
<td ng-bind="::result.title"></td>
<td> <button type="button" class="btn" ng-click='ctrl.deleteItem(result)'>Delete</button></td>
</tr>
</tbody>
And in my controller I have:
vm.deleteItem = function (result) {
myService.deleteItem(result.id)
.then(function (response) {
vm.result.splice(result, 1);
});
};
As you see, the vm.result has changed if the item be deleted successfully.
Now, the item deleted in db, so we have response and then the item has been removed from vm.result, too. But the list hasn't updated in browser.
As you see, I use controller as approach and not $scope .
Try deleting the item this way:
vm.result.splice(vm.result.indexOf(result), 1);
The first Splice parameter should be the index of element rather than element itself.
var index = vm.result.findIndex(function(item) {
if (item.id == test.id) {
return true;
}
});
if (index !== -1) {
// Removing the test from list;
vm.result.splice(index, 1);
}
check based on id from the array test.id is the id of the element u r deleting

How can I easily filter on more than one property?

Using Angular v1.5 I've got a simple one property filter working but I would like to filter on two properties. Searching came up with some custom filters but that seemed like a bunch of code to just look at an extra property.
In my below example I would like the filter to work on both FirstName and LastName.
Filter Name: <input type="text" ng-model="memberFilter.FirstName" />
<p />
<div class="table-responsive">
<table class="table table-bordered table-striped table-hover">
<tr class="info">
<th ng-click="doSort('FirstName')">First Name</th>
<th ng-click="doSort('LastName')">Last Name</th>
<th ng-click="doSort('EmailPrimary')">Email</th>
<th ng-click="doSort('PhonePrimary')">Phone</th>
<th> </th>
</tr>
<tr ng-repeat="member in members | filter:memberFilter | orderBy:sortBy:reverse">
<td>{{ member.FirstName }}</td>
<td>{{ member.LastName }}</td>
<td>{{ member.EmailPrimary }}</td>
<td class="text-center">{{ member.PhonePrimary | tel }}</td>
<td class="text-center">View</td>
</tr>
</table>
</div>
I tried adding an array to the ng-model but that didn't work:
ng-model="[memberFilter.FirstName,memberFilter.LastName]"
Updated Question
I'm new with Angular in general and just wrote my first custom filter the other day to display formatted telephone numbers. You can see my filter in the original code but I changed the name from "tel" to "phone". It's one I found on SO and I was able to get it to work. So I assumed I could just add the search filter to this file and not create a new js file for each filter. However, when I added it my Angular stopped working. I thought I added it correct but I might have a semi-colon in the wrong spot or maybe it's not possible. I still haven't figured out a good way to debug in Angular.
Here is a file I created for my filters called filter.js.
angular.module('appFilters', [])
.filter('phone', function () {
return function (phone) {
if (!phone) { return ''; }
var value = phone.toString().trim().replace(/^\+/, '');
if (value.match(/[^0-9]/)) {
return phone;
}
var country, city, number;
switch (value.length) {
case 10: // +1PPP####### -> C (PPP) ###-####
country = 1;
city = value.slice(0, 3);
number = value.slice(3);
break;
case 11: // +CPPP####### -> CCC (PP) ###-####
country = value[0];
city = value.slice(1, 4);
number = value.slice(4);
break;
case 12: // +CCCPP####### -> CCC (PP) ###-####
country = value.slice(0, 3);
city = value.slice(3, 5);
number = value.slice(5);
break;
default:
return phone;
}
if (country == 1) {
country = "";
}
number = number.slice(0, 3) + '-' + number.slice(3);
return (country + " (" + city + ") " + number).trim();
};
})
.filter('customMemberFilter', function () {
return function (memberList, query) {
// make sure a query value was passed
if (query) {
query = query.toLowerCase();
var out = [];
angular.forEach(memberList, function (member) {
if ((member.FirstName.toLowerCase().includes(query)) ||
(member.LastName.toLowerCase().includes(query))) {
out.push(member);
}
});
return out;
} else {
return memberList;
}
}
});
and this is my app.js where the appFilters are added
(function () {
var app = angular.module('troopApp', ['ngRoute','appFilters']); //('moduleName', [array of injected modules])
app.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MembersController',
templateUrl: 'app/views/members.html'
})
.when('/memberDetail/:memberId', {
controller: 'MemberDetailController',
templateUrl: 'app/views/memberDetail.html'
})
.otherwise({ redirectTo: '/'});
});
}());
This is what I changed my HTML code to:
Filter Name: <input type="text" ng-model="memberFilter" />
and
<tr ng-repeat="member in members | customMemberFilter:memberFilter | orderBy:sortBy:reverse">
The solution is very simple.
Change this line:
Filter Name: <input type="text" ng-model="memberFilter.FirstName" />
to this:
Filter Name: <input type="text" ng-model="memberFilter" />
By default Angular will do deep property filtering. Since you were creating an object with a FirstName property to use as your filter you were effectively limiting the filter to that property on your target object(s). By making the filter more generic Angular will attempt to match on any property of the target object(s).
Update: This will, of course, match on all properties of your member object which may be undesirable. If this is the case then, as you suspected, you'll have to write a custom filter. Here's one way you could write it:
.filter('customMemberFilter', function() {
return function(memberList, query) {
// make sure a query value was passed
if (query) {
query = query.toLowerCase();
var out = [];
angular.forEach(memberList, function(member) {
if ((member.FirstName.toLowerCase().includes(query)) ||
(member.LastName.toLowerCase().includes(query))) {
out.push(member);
}
});
return out;
} else {
return memberList;
}
}
})
And then you would use it:
<tr ng-repeat="member in members | customMemberFilter:memberFilter | orderBy:sortBy:reverse">

Resources