ngResource GET with filter values - angularjs

I'm writing a small test application where I can retrieve my customers from a parse.com database.
I have the following form in html
...
<body ng-app="myApp">
<div ng-controller="CustomerController">
<button ng-click="getCustomers()">Get customers</button>
<ul>
<li ng-repeat="customer in customers">{{ customer.name }}</li>
</ul>
</div>
</body>
...
My angular app is the following:
Module
var app = angular
.module('myApp', ['ngResource'])
.constant('myConfig', {
'api_url': 'https://api.parse.com/1/classes/',
'parse_application_id': 'xxxxxxxxxxxxx',
'parse_rest_api_key': 'xxxxxxxxxxxxx'
});
Factory
app.factory('CustomersService', function($resource, myConfig) {
return $resource(myConfig.api_url + 'Customer', {}, {
query: {
method: 'GET',
isArray: false,
headers: {
'X-Parse-Application-Id': myConfig.parse_application_id,
'X-Parse-REST-API-Key': myConfig.parse_rest_api_key
}
},
create: {
method: 'POST',
headers: {
'X-Parse-Application-Id': myConfig.parse_application_id,
'X-Parse-REST-API-Key': myConfig.parse_rest_api_key
}
}
})
});
Controller:
app.controller('CustomerController', function($scope, CustomersService, CustomerService) {
$scope.getCustomers = function() {
CustomersService.query().$promise.then(function(result) {
$scope.customers = result.results;
});
};
});
So when I click my button, everything works like it should.
But I also want to add a filter by name when I want to retrieve customers from the database.
When I execute the following in Postman
https://api.parse.com/1/classes/Customer?where={"name":"aaaaa"}
this works and only gets the customer with the name "aaaaa". So I know that the syntax is OK.
So I will add a textbox where the user can enter a customername and after that I want to click on the search button.
But how can I manage the ?where={"name":"aaaaa"} into the angular stuff when I click the button? I also want to expand the filter with other columns from that customer.

Something like this should work (assuming everything goes in the where object)
Add some search fields that bind to a scoped object's properties. We'll call it search
<label for="search_name">Name</label>
<input type="text" ng-model="search.name" name="name" id="search_name">
<label for="search_city">City</label>
<input type="text" ng-model="search.city" name="city" id="search_city">
Then you can execute the query action with
CustomersService.query({where: $scope.search}).$promise...
That should create a query param like
?where=%7B%22name%22%3A%22aaaaa%22%2C%22city%22%3A%22London%22%7D
which is the URI encoded value
?where={"name":"aaaaa","city":"London"}

Related

angularjs highlight the first item in select

After the initial call to get the list of items (see below), I need get select the first item and get more details from my database. So after the items load into my select input I need to :
Highlight the first item in listbox
Pass that first itemID to DB to fetch the details of that item.
How can I do all of this within my initial page load?
<!DOCTYPE html>
<html>
<head>
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<script>
var IM_Mod_app = angular.module('IM_ng_app', []);
IM_Mod_app.controller("IM_Ctrl", function ($scope, $http) {
var PlaId = "DFC";
$http({
method: 'GET',
url: 'http://xxx/api/ItemMaintenance/GetAllFilteredItems',
params: { PlaId: PlaId }
}).then(function successCallback(response) {
$scope.items = response.data;
}, function errorCallback(response) { });
});
</script>
</head>
<body ng-app="IM_ng_app">
<table ng-controller="IM_Ctrl">
<tr>
<td>
#*<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items" ng-class="{selected: $index==0}" ng-change="onItemSelected(itm.ITEM_ID)">*#
#*<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items track by itm.ITEM_ID" ng-selected="$first" >*#
<select ng-model="itm" size="10" ng-options="itm.ITEM_ID for itm in items track by itm.ITEM_ID" ng-init="items[0].ITEM_ID">
<option value="" ng-if="false"></option>
</select>
</td>
</tr>
</table>
</body>
</html>
Your ng-init isn't working as you expect because your array does not have any data when the page loads. Instead, it has to complete the $http call before any of the data is available. This just means that you need to finish your work when your $http call comes back, (in the .then).
Your updated AJAX call might look like this
$http({
method: 'GET',
url: 'http://xxx/api/ItemMaintenance/GetAllFilteredItems',
params: { PlaId: PlaId }
}).then(function successCallback(response) {
$scope.items = response.data;
//Initial the select box
$scope.itm = $scope.items[0];
//Get the details
getSelectedItemDetails();
}, function errorCallback(response) { });
function getSelectedItemDetails() {
$http({}) //whatever API endpoint to get the details
.then(function (response) {
// do something with the data. Maybe extend $scope.itm?
})
}
Moving forward, I discourage using ng-init. Instead, just initialize the value of your variables in your javascript. Because of angular's two-way binding, any updates to the value from the javascript will make it to the HTML.
Try initialising $scope.itm
Let's say I have
<select ng-model="whatever">
<option value="hello">bye</option>
<option value="hello2">..</option>
</select>
If you initialise $scope.whatever = "hello" bye will be displayed in the select

ng-repeat not showing from my factory

I cannot get some data from my factory:
.factory("userDataFactory", function(){
var user;
var user_notes;
var interfaz = {
getUsuario: function(){
return user;
},
getNotes: function(){
return user_notes;
},
nuevoUsuario: function(userId, email){
user = [userId, email];
},
addNotes: function(notes){
user_notes = notes;
}
}
return interfaz;
})
What I do first is to populate the factory with data from my Ruby Api using this code:
$http({
method : "POST",
url: "http://localhost:3000/api/v1/checkuser",
data: json
}).then ( function mySucces(response){
userDataFactory.nuevoUsuario(response.data.user[0].id, response.data.user[0].email);
userDataFactory.addNotes(response.data.notes);
$state.go('thirdday');
And later on Im calling my factory in a new controller:
.controller('ListNotes', function($scope, userDataFactory, $state){
$scope.notes = userDataFactory.getNotes();
console.log($scope.notes);
//console.log($scope.notes[0].note1);
})
and finally, trying to show it in my html (listnotes.html)
<div class="list">
<a class="item" href="#" ng-repeat="x in notes">
{{ x.note2 }}
</a>
</div>
my routes config just in case:
.state('list',{
url: '/listnotes',
templateUrl: 'templates/listnotes.html',
controller: 'ListNotes'
})
so, what am I missing? why is not showing all the notes I got from the API?
Thanks in advance
EDIT
After I get the data from my API I go to 'thirdday.html' view and I just press a button to go to the list view.
.state('thirdday',{
url: '/thirdday',
templateUrl: 'templates/thirdday.html',
controller: 'Notes'
})
In your factory 'user_notes' contains object with key 'note1' (according to your log statement console.log($scope.notes[0].note1)). and in ng-repeat you are using x.note2. Make it x.note1.
try to add notes {{notes}} in html. see if it has value in there.
may be you just not add ng-app or ng-controller or someting in the mark up

How to do global search in Angularjs from json array?

Iam able to display and filter search results in the same view..But how can i create search box in header navbar which is common to all pages. On click of search button should open the separate page and should load the search results alphabetically from json array based on the value entered in search box. How to do this? Kindly help
This is one way of attacking your problem. If i understood your problem correctly you wanted to filter out a JSON array...
So lets say in mainCtrl we have this:
$http({
method: 'GET',
url: '/Users'
}).then(function successCallback(response) {
$scope.usersJson = response;
}, function errorCallback(response) {
console.error("Something Happened...");
});
So lets say that data above gives us a sample of Users that look like this:
"Username" : {
"name" : "Username",
"value" : "Hello World"
}
Then in our html if we want to go through the data:
<body ng-app="app" ng-controller="mainCtrl">
<input type="text" ng-model="search" />
<p ng-repeat="message in messages | filter: search">
Name: {{ message.name }}
Message : {{message.value}}
</p>
</body>
You have to learn more about the ngFilter Directive and Filtering in AngularJS In general.. Here is the docs about it.. Hope this helped!
EDIT
If you want to do this in multiple controllers, just make a service to serve as a communication beetween controllers...
app.service("jsonArray", function($scope){
this.getArray = function(){
$http({
method: 'GET',
url: '/Users'
}).then(function successCallback(response) {
return response;
}, function errorCallback(response) {
console.error("Something Happened...");
});
}
})
Now you can inject this service to a controller and simply do jsonArray.get() to get the JSON List..
How to inject service into controller?
Sample:
app.controller('mainCtrl', ["$scope", "jsonArray", function($scope, jsonArray){
}])
Hope this helped..

Search Toolbar with AngularJS

This is a newbie question about Angular 1.4.
My Main Question
I have the following search view:
'use strict';
var module = angular.module('myapp.search', ['ngRoute', 'ngResource']);
module.config(function ($routeProvider) {
$routeProvider.when('/search', {
templateUrl: 'search/search.html',
controller: 'SearchCtrl'
});
});
module.factory('Search', function ($resource) {
return $resource('http://www.myapp.com/api/search', {}, {
query: {
method: 'GET',
params: {},
isArray: false
}
});
});
module.controller('SearchCtrl', function ($scope, Search) {
$scope.results = [];
$scope.query = '';
$scope.doSearch = function (query) {
Search.query({q: query}).$promise.then(function (result) {
$scope.results = result.results;
});
};
});
And the partial HTML (search.html):
#search.html
<input placeholder="search" ng-model="query" />
<button ng-click="doSearch(query)" />
<h1>Results</h1>
<ol>
<li ng-repeat="result in results">{{ result }}</li>
</ol>
...
This works perfectly, the problem is when I want to put the search input in a toolbar (defined in index.html):
#index.html
<div ng-controller="SearchCtrl">
<div class="toolbar">
<input placeholder="search" ng-model="query" />
<button ng-click="doSearch(query)">
</div>
...
In this case, by pushing the search button the query is executed in the back-end but the results are not updated in $scope. what's wrong? I've tried calling $scope.$apply() with no luck. I'm lost with this.
Bonus Question
Given that the search functionality is in the toolbar (always visible) users can execute queries in any place of the website. How can I redirect the response to http://www.myapp.com/search?
Thanks in advance.
You have two distinct instances of SearchCtrl, each with its own distinct scope: one in the navbar (dur to ng-controller="SearchCtrl"), and one in the main view (due to controller: 'SearchCtrl').
So the search in the navbar modifies the scope of the navbar controller, and the scope of the main view doesn't know anything about it.
If you want to got to the search main view when something is searched in the navbar, simply use
$location.url('/search?query=' + theEncodedQueryTypedByTheUser);
And in the search route's resolve function, or in its controller, get the route param named query, send the HTTP request, and update the scope with the results.

Typehead displays wrong on certain input

I am using a uiTypehead for input selection.
It works well except for a simple fact. My inputs always have the form like
{name: "Las Vegas McCarran International (LAS)<span
class="country">United States</span>", iata: "LAS"}
So I insert <span class="country">...</span> from my backend into the string.
When I then type in "veg" into the input field, that's all fine.
However, when typing in "las" instead, following happens:
What basically happens is, that my system assumes "class" to be part of my desired string does the following in the view:
<span c<strong="">lass="country">United States</span>
Basically, it recognizes "las" as the string and puts a strong into that part so that it is not displayed correctly.
My view, service and my controller look as follows:
Service:
angular.module('tripdeltaApp').service('airportService',['$http',function($http){
this.airport = function (entry) {
return $http({
method: 'POST',
url: '/airport',
data: {'search': entry}
}).then(function (response) {
return response.data.map(function (item) {
//console.log(item);
return item;
});
});
};
}]);
Controller:
$scope.onSelect = function ($item, $model, $label,to,index) {
$model = urlParser.cleanAirport($model);
if(to && $scope.flightArray[index+1] && !$scope.flightArray[index+1].from) {
$scope.flightArray[index+1].from = $model;
}
};
and view:
<input type="text"
ng-focus="inputFocus=false"
ng-blur="inputFocus=true"
ng-model="flight.to"
placeholder="{{'TO'|translate}}"
name="arrivalAirport"
typeahead="data as data.name for data in getAirport($viewValue)"
class="form-control"
typeahead-editable="false"
typeahead-on-select="onSelect($item, $model, $label,1,$index)"
autocomplete="off"
select-on-click
required>
Any idea how to solve that?
I think your best bet is to use a Custom Template, as described in the Typeahead example with the flags, instead of putting markup into your data.
You'd change your data to be like this:
{name: "Las Vegas McCarran International (LAS)", country: "United States", iata: "LAS"}
and use a template something like this:
<script type="text/ng-template" id="customTemplate.html">
<div>
{{match.model.name}}
<span class="country">{{match.model.country}}</span>
</div>
</script>
Update
If you can't change the data on the backend, you could preprocess your data as it gets loaded into JavaScript:
var re = new RegExp('^([^<]+)<span class="country">([^<]+)<\/span>');
angular.module('tripdeltaApp').service('airportService',['$http',function($http){
this.airport = function (entry) {
return $http({
method: 'POST',
url: '/airport',
data: {'search': entry}
}).then(function (response) {
return response.data.map(function (item) {
//console.log(item);
var matches = item.name.match(re);
item.name = matches[1];
item.country = matches[2];
return item;
});
});
};
}]);
The regular expression may need some tweaking, based on the specific data you have. If any airport "name" fields have a "<", that would obviously cause trouble. You may also need to mess with spacing, location of quotes, etc.

Resources