I have to debug a snippet written in AngularJS.
//===== service ==
app.service('allUserService', function($http) {
var config = {
headers: {
'X-XSRF-TOKEN': gettingValueFromSomewhere()
}
};
this.getAll = function() {
var restUrl = CONTEXT_PATH + '/rest/path/mypath';
return $http.get(restUrl, config).then(function(response) {
console.log(response.data.body); // console prints an Array which is correct
return response.data.body;
});
}
});
//========= controller ====
app.controller('UserCtrl', function($scope,allUserService) {
var valueArray = [];
valueArray = allUserService.getAll();
console.log(valueArray);
$scope.faqBook = valueArray;
});
allUserService :I am getting correct result from Rest webservie and console log shows desired return (an Array)
faqUserCtrl : I am not getting desired value in console log. Pls help me in finding the issue. It should have an array. I am expecting an Array in $scope.faqBook.
Important to Note, when I return a hardcoded array from allUserService, the code works fine
<div class="container" ng-app="UserModule" ng-controller="UserCtrl">
<p>Search : <input type="text" ng-model="search"/></p>
<table id="mainTable" class="table table-striped table-hover">
<tr ng-repeat="x in faqBook | filter:search">
<td><ul class="list-group"><li class="list-group-item">Question: {{ x.question }}</li><li class="list-group-item"> Answer: {{ x.answer }}</li></ul></td>
</tr>
</table>
</div>
Related
Example: plunker
From the above example, I have created a simple form with filter option using angular.
As far as the filter concern, it's a default filter which is provided by angular. Currently, when I search the text "br", it shows the id 1 and 10.
I would like to add the regEx in the search input.The search can be done using regEx.
what I need is, The search item can be
"br" => It show two data,
"b*" => Show all the data starts with b.
"*" => All the data
"*br" => All the data ends with br.
The above search should show the relevant data as per the search input.
scripts.js
var app = angular.module('app',[]);
app.controller('regEx', function($scope, $http) {
$scope.init = function() {
$http.get('https://jsonplaceholder.typicode.com/users/').success(function(data) {
$scope.data = data;
console.log(data);
}).error(function(e) {
console.log(e);
});
}
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-controller="regEx" class="container">
<h1>RegEx in Angular search</h1>
<input type="text" class="form-control" ng-model="search" autofocus>
<br />
<table ng-init="init()" class="table table-bordered animated fadeIn">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Phone Number</th>
<th>username</th>
<th>website</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="d in data | filter:search">
<td>{{d.id}}</td>
<td>{{d.name}}</td>
<td>{{d.phone}}</td>
<td>{{d.username}}</td>
<td>{{d.website}}</td>
</tr>
<tr ng-if="d.length < 1">
<td colspan="5" class="text-center">No Router Found</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
In this case I would probably create a custom filter.
The tricky part here is that your object model is not flat, so we have to do a deep traversal to check the fields. The caveat to this approach is that you could potentially be checking against fields that are not visible (although i believe this is how the default angular filter behaves).
If that is an issue, you could adjust the filter to pass in a list of fields to check against and use those to filter out unwanted fields.
Here is the filter :
app.filter('wildcard', function() {
return function(list, value) {
if (!value) {
return list;
}
var escaped = value.replace(/([.+?^=!:${}()|\[\]\/\\])/g, "\\$1");
var formatted = escaped.replace('*', '.*')
if (formatted.indexOf('*') === -1) {
formatted = '.*' + formatted + '.*'
}
var output = []
angular.forEach(list, function(item) {
var regex = new RegExp('^' + formatted + '$', 'im');
if (traverse(item, regex)) {
output.push(item);
}
});
return output
}
function traverse(item, regex) {
for (var prop in item) {
//angular property like hash
if(prop[0] === '$$'){
return;
}
var value = item[prop];
if (typeof value === 'object') {
traverse(value, regex);
}
if(regex.test(value)){
return true;
}
}
}
})
And then in you html :
<tr ng-repeat="d in data | wildcard:search">
Here is the plunker
I've been trying to call passID() function when page initializes but the function still doesn't work.
The website works this way:
Page-A passes data to Controller-A
then to Service then to Controller-B then the function from Controller-B gets called by Page-B.
My guess is that my error is in Page-B since I've successfully passed the data of Page-A up to Controller-B but I'm not 100% sure.
In my Page-A, I've made a button calling the function of Controller-A using ng-Click
<button class="viewDetails" ng-click="passID([1,03,07])">test button</button>
Controller-A only gets data from Page-A
angular.module('handsetExplorerModule')
.controller("compareHandsetController", ['$scope','compareHandsetService','sharedData', function($scope, compareHandsetService, sharedData) {
$scope.passID = function(id){
var arrayID = [];
arrayID = id;
sharedData.set(arrayID);
};
}]);
Service gets my JSON and is my getter and setter
angular.module('handsetExplorerModule')
.factory('compareDetailsService', ['$http','$q', function($http, $q) {
return {
getHandsetList: function(){
return $http.get("./data/compareJSON.json");
}
};
}]);
angular.module('handsetExplorerModule')
.factory('sharedData', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
Controller-B filters the JSON file to only get what I need (i used ID from Page-A to filter)
angular.module('handsetExplorerModule')
.controller("compareDetailsController", ['$scope','compareDetailsService','sharedData', function($scope, compareDetailsService, sharedData) {
$scope.data = {phones: []};
compareDetailsService.getHandsetList()
.then(
function(data){
$scope.data.phones = data.data;
},
function(error){
//todo: handle error
}
);
var getData = sharedData.get();
$scope.passID = function passID(){
var newData = [];
for(var i=0; i<$scope.data.phones.length; i++){
if($scope.data.phones[i].id == getData[0] || $scope.data.phones[i].id == getData[01] || $scope.data.phones[i].id == getData[02]){
newData.push($scope.data.phones[i]);
}
}
$scope.phoneContent = newData;
}
$scope.viewDetails = function(id){
alert(id);
}
}]);
Lastly, In my Page-B, I've called Controller-B function: <div ng-init="passID()">
to be used by ng-repeat of my Page-B:
<table id="Content" ng-repeat="x in phoneContent track by x.id">
<tr>
<td class="one">
<table>
<tr>
<td><img class="contImage" ng-src="{{x.image}}" ng-alt="{{x.name}}" /></td>
<td class="textAlign">{{x.name}} <button class="viewDetails" ng-click="viewDetails(x.id)">VIEW DETAILS</button></td>
</table>
</td>
<td class="two">{{x.size}}</td>
<td class="one">{{x.storage}}</td>
<td class="two">{{x.camera}}</td>
<td class="one">{{x.battery}}</td>
<td class="two">{{x.network}}</td>
<td class="one">{{x.sim}}</td>
</tr>
</table>
I don't know why you define arrayID.
To solve your problem try with sharedData.set = arrayID; instead of sharedData.set(arrayID);.
Hope it helps!
I am getting the below error while using angular.js filter methos.
Error:
TypeError: Cannot read property 'length' of undefined
at adminCustomerViewController.js:1387
at fn (eval at compile (angularjs.js:212), <anonymous>:4:464)
at dirPagination.js:100
at Object.<anonymous> (angularjs.js:115)
at n.$digest (angularjs.js:130)
at n.$apply (angularjs.js:133)
at g (angularjs.js:87)
at K (angularjs.js:91)
at XMLHttpRequest.z.onload (angularjs.js:92)
I am explaining my code below.
<input class="form-control" placeholder="Type Restaurant Name" name="q" type="text" ng-model="letter">
<tr dir-paginate="cus in ($parent.labelResults=(listOfCustomerData | startsWithLetter:letter | orderBy:'rest_name')) | itemsPerPage:5 track by $index" current-page="currentPage">
<td>{{itemsPerPage *(currentPage-1)+$index+1}}</td>
<td>{{cus.rest_name}}</td>
</tr>
</tbody>
My controller side code is given below.
customerView.filter('startsWithLetter', function () {
return function (items, letter) {
//console.log('items',items);
var filtered = [];
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.rest_name.substring(0, 1))) {
filtered.push(item);
}
}
return filtered;
};
});
customerView.controller('adminCustomerViewController',function($scope,$state,$http,$window,$timeout,Upload,focusInputField){
$http({
method:'GET',
url:"php/customerInfo.php?action=disp",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function successCallback(response){
console.log('res',response.data);
$scope.listOfCustomerData=response.data;
},function errorCallback(response) {
})
})
Actually i am implementing the search functionality here . Here my requirement is when user will type at least first letter of the restaurant name(i.e-rest_name) the related restaurant will filter from the table. Suppose i have many restaurant like Anjum,A&P Chinese Food Express,Bookers BBQ & Crab Shack,Butcher And The Baker, Cactus Club Stephen Avenue,Cactus Club - Macleod Trail. Here when user is typing only a inside the search box the names started with a should filter . I did something but got the above error.Please help me.
Since you want only those objects that have the corresponding letters to input
you don't need to use Regexp.
Here a snippet working:
var app = angular.module('app', [])
.controller('mainCtrl', function($scope) {
$scope.countries = [
{
"name":"USA"
},
{
"name":"Japan"
},
{
"name":"France"
},
{
"name":"Canada"
},
{
"name":"China"
}
];
})
.filter('startsWith', function() {
return function(items, search) {
if (!search) {
return items;
}
search = search.toLowerCase();
return items.filter(function(element) {
return element.name.toLowerCase().substring(0, search.length).indexOf(search) != -1;
});
}
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<label for="letter">Filter: </label>
<input type="text" id="letter" ng-model="letter">
<hr>
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="country in countries | startsWith: letter">
<td ng-bind="country.name"></td>
</tr>
</tbody>
</table>
</body>
</html>
Try this
<input class="form-control" placeholder="Type Restaurant Name" name="q" type="text" ng-model="letter">
<tr dir-paginate="cus in ($parent.labelResults=(listOfCustomerData | filter : letter )) | itemsPerPage:5 track by $index" current-page="currentPage">
<td>{{itemsPerPage *(currentPage-1)+$index+1}}</td>
<td>{{cus.rest_name}}</td>
</tr>
</tbody>
its best to use filter given in angular as comapred to make your custom filter
I'm trying to compare an old value in a <td> with the new value entered by the end user. I'm using ng-blur to detect when there is focus out of the field rather than calling the function. The problem is I can't get this very simple logic to work and I can't figure out why.
This is my table:
<main ng-controller="mainCtrl">
<table class="table table-bordered table-hover" ng-controller="tableCtrl">
<p ng-model="old">{{old}}</p>
<thead>
<th>user name</th>
<th>script name</th>
<th>cron format<span class="glyphicon glyphicon-question-sign" data-toggle="tooltip" data-original-title="Min|Hour|Day Of Month|Month|Day Of Week"></span></th>
</thead>
<tbody ng-repeat="(user_id,script_id) in data">
<tr ng-repeat="(script_id, cron_format) in script_id">
<td class="userName">{{user(user_id)}}</td>
<td class="scriptName">{{script(script_id)}}</td>
<td class="cronFormat"><input type="text" ng-model="cron_format" ng-blur="saveCron(user_id,script_id,cron_format)"/></td>
</tr>
</tbody>
</table>
and this is the comparison :
$scope.old = $scope.cron_format = "";
$scope.saveCron(user_id, script_id, cron_format) {
if ($scope.old == $scope.cron_format) {
return; //value was unchanged
}
$.post("updateCronChange.php", "user_id=" + userId + "&script_id=" + scriptId + "&cron_format=" + cronFormat, function (data) {
alert('cron format changed to:' + cronFormat);
});
$scope.old = $scope.cron_format;
});
Currently, the function executes each time the field is out of focus. What am I missing here?
You can use ng-init for each iteration of the ng-repeat to store the old value, and then use it in the function to compare:
<tr ng-repeat="row in data" ng-init="oldCron = row.cron_format">
And in the function call:
ng-click="saveCron(row.user_id,row.script_id,row.cron_format,oldCron)"
And finally inside the function itself:
$scope.saveCron = function(userId,scriptId,cronFormat,oldCron){
console.log("old cron: " + oldCron);
console.log("new cron: " + cronFormat);
if (oldCron != cronFormat) {
//assign
}
}
Fiddle.
If I understand you correctly, you are trying to save an old value and print it out. You can try changing it to this -
if ($scope.old != $scope.cron_format) {
$.post("updateCronChange.php", "user_id=" + userId + "&script_id=" + scriptId + "&cron_format=" + cronFormat, function(data) {
alert('cron format changed to:' + cronFormat);
});
$scope.old = $scope.cron_format;
}
Here is a working example if you like -
var test = angular.module('test', []);
test.controller('TestCtrl', ['$scope',
function($scope) {
$scope.myModel = '';
$scope.old = '';
$scope.getNewValue = 'false'
$scope.saveModel = function(value) {
if ($scope.old != value) {
$scope.getNewValue = 'true';
$scope.old = value;
$scope.myModel = '';
// Here you can do your post request
} else {
$scope.getNewValue = 'false';
}
};
}
]);
.green {
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app='test'>
<div ng-controller="TestCtrl">Enter Some Text
<input type="text" ng-model="myModel" ng-blur="saveModel(myModel)">
<p>Old Value - {{old}}</p>
<p>Current Value - {{myModel}}</p>
<p class="green">Get New Value - {{getNewValue}}</p>
</div>
</div>
I have a list with items. Each item of a list can be selected. If I select the item, it will be pushed in the cookies.
In my home.html (here I have the list with the items that I can add to cookies)
<table class="table" >
<tr data-ng-repeat="item in items">
<td><span >{{item.title}}</span></td>
<td> <button data-ng-click="addToCookies(item)" data-ng-disabled="item.added" class="btn">
<span data-ng-show="!item[$index].added" class="text-center">Add To cookies</span>
<span data-ng-show="item[$index].added" class="text-center">Added To cookies</span>
</button>
</td>
</tr>
<tr></tr>
</table>
In page cookies.html I call the getCookiesItem() and the directive :
<div class="navbar navbar-right" data-ng-controller="ctrlItemsList">
<div data-item-list data-items="getCookiesItem()" ></div>
</div>
In my controller I did :
//TO ADD ELEMENT SELECTED IN THE COOKIE
$scope.addToCookies = function (item){
item.added=true;
angular.extend($scope.criteria, item);
cookiesItems.addItem($scope.criteria);
}
//TO GET ELEMENTS COOKIE (MAYBE I HAVE TO DO A $WATCH OF THIS FUNCTION)
$scope.getCookiesItem = function (){
return cookiesItems.getItems();
}
In my service I have :
Cservices.factory('cookiesItems', ['$cookieStore', function($cookieStore) {
var items = [];
return {
addItem: function( itemSelected){
var array = [];
if ($cookieStore.get('key') === undefined) {
$cookieStore.put('key', []);
}else{
array = $cookieStore.get('key');
}
array.push(itemSelected);
$cookieStore.put('key', array);
},
removeItem: function(itemSelected){
var array = $cookieStore.get('key');
if(array != undefined){
for (var i = 0; i < array.length; ) {
if (array[i].id=== itemSelected.id) {
array.splice(array[i], 1);
} else {
++i;
}
}
}
$cookieStore.put('key', array);
},
getItems: function(){
return $cookieStore.get('key');
}
The elements cookies are print in the following directive:
template :
<table class="table" >
<tr data-ng-repeat="item in items">
<td>{{item.title}}</td>
</tr>
<tr></tr>
</table>
in the js :
iDirective.directive('itemList', function() {
return {
restrict: 'A',
transclude: true,
scope: {
items: '=items'
}
templateUrl: ''
};
});
I have the following error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: [["fn: parentValueWatch; newVal: [{
and when i try to add the 10' element in the cookies I have this error (only 9 element I am able to store): Cookie '' possibly not set or overflowed because it was too large (4263 > 4096 bytes)! -
I am not able to resolve it..someone can help me?
Thanks
It would be helpful if you could put together a jsfiddle example.
From your code I can see the following issue.
In the ng-repeat section either should use 'items[$index]' or just 'item'.
<table class="table" >
<tr data-ng-repeat="item in items">
<td><span >{{item.title}}</span></td>
<td> <button data-ng-click="addToCookies(item)" data-ng-disabled="item.added" class="btn">
<span data-ng-show="!item.added" class="text-center">Add To cookies</span>
<span data-ng-show="item.added" class="text-center">Added To cookies</span>
</button>
</td>
</tr>
<tr></tr>
</table>
What is the method addToCookies exactly doing? What is $scope.criteria object? It looks like you always modify and add the same object to the cookieItems.
$scope.addToCookies = function (item){
item.added=true;
angular.extend($scope.criteria, item); // what is $scope.criteria?
cookiesItems.addItem($scope.criteria); // will always the same object added to the cookieItems?
$scope.selectedItems.push(item); // why do you have a second list and why you add 'item' and not 'criteria'?
}