I am trying to make auto suggest in angular Js, if I have to find a string in an array i can use indexOf method,based on index value,I can get the suggestions.
But how should I match string in an array of Object?
I have an array of object
$scope.array=[
{"name":"stackoverflow","id":1},
{"name":"sunny","id":2},
{"name":"san","id":3},
{"name":"bat","id":4},
{"name":"ball","id":5}
]
so In a text box if I type "st",it should give me result in an array [{stackoverflow","id":1}]
if I enter "ba",it should give me result in an array [{"name":"bat","id":4},
{"name":"ball","id":5}]
inside Controller
$scope.searchString=function(){
//what logic should I write here?
}
you can use filter for that
<input type="text" ng-model="searchText" />
<div ng-repeat="item in array | filter:{'name':searchText}">
{{item}}
</div>
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.array=[
{"name":"stackoverflow","id":1},
{"name":"sunny","id":2},
{"name":"san","id":3},
{"name":"bat","id":4},
{"name":"ball","id":5}
]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="searchText" />
<div ng-repeat="item in array | filter:{'name':searchText}">
{{item}}
</div>
</div>
using custom function
angular.module("app",[])
.controller("ctrl",function($scope){
var backUp=[
{"name":"stackoverflow","id":1},
{"name":"sunny","id":2},
{"name":"san","id":3},
{"name":"bat","id":4},
{"name":"ball","id":5}
]
$scope.array = angular.copy(backUp)
$scope.changeText = function(){
$scope.array = backUp.filter(function(o){
return o.name.startsWith($scope.searchText)
})
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="searchText" ng-change="changeText()"/>
<div ng-repeat="item in array">
{{item}}
</div>
</div>
Here are your solutions,
Pure JS:
/*
input -> object array
searchStr -> string
keyToSearch -> string array - match to restrict within given keys //eg:['name','id','somekey']
*/
function filterObjectArray(input, searchStr, keysToSearch){
return input.filter(function(obj){
var hasMatch = false;
var hasKeySearch = (keysToSearch && keysToSearch.length)
for(k in obj){
if(!hasMatch){
hasMatch = (!hasKeySearch || (hasKeySearch && keysToSearch.indexOf(k))) && (new RegExp(searchStr, 'gi')).test(obj[k]);
}
}
return hasMatch;
});
}
console.log(filterObjectArray($scope.array, 'ba')); //[{"name":"bat","id":4},{"name":"ball","id":5}]
console.log(filterObjectArray($scope.array, '1')); //[{"name":"stackoverflow","id":1}]
console.log(filterObjectArray($scope.array, 's', ['name'])); //[{"name":"stackoverflow","id":1},{"name":"sunny","id":2},{"name":"san","id":3}]
With Angular,
Solution 1:
You can use $filter service in your method.
$scope.searchString = function(str){
return $filter('filter')($scope.array, str);
};
Solution 2:
With filter in template,
<input type="text" ng-model="searchText" />
<div ng-repeat="item in array | filter:{'name':searchText}">
{{item}}
</div>
To answer your question directly, this should work:
$scope.searchString=function(str){
const results = [];
const len = str.length;
for(const item of $scope.array){
const test = item.name.substr(0, len);
if(str === test){
results.push(item);
}
}
return results;
}
Though, the method regarding filters from #sachila probably makes sense in your situation.
I would probably use a .reduce() on the array, then check each object item for a match. Something like:
var desiredResults = $scope.array.reduce(function(p,c){
for(key in c){
if(c[key].indexOf("valueToMatch") > -1){
p.push(c);
next();
}
}
return p;
},[])
I have not tested this code, but it's the general idea.
Related
I want want to display and count only batter in batters at index 0.
i.e id = 1001 type = regular
and count should be "4"
Maybe this updated JSFiddle will give you an idea.
HTML
<div ng-app="myApp" ng-controller="customersCtrl">
<ul ng-repeat="x in myData">
<li ng-repeat = "batter in x.batters.batter | filter: {'id': 1001, 'type': 'Regular'}">
{{ batter.id }} - {{ batter.type }}
</li>
</ul>
{{countBatters(1001, 'Regular')}}
</div>
Added function in controller:
$scope.countBatters = function(id, type) {
return $scope.myData.filter(function(obj) {
var batter = obj.batters.batter[0];
return batter.id == id && batter.type == type
}).length;
}
Use array filter method..
var getBatter1001 = (item) => { return item.batters.batter.filter((x) => {x.id === '1001'}); }
var batter1001 = $scope.myData.filter(getBatter1001);
console.log('Count of objects with batter id 1001: '+batter1001.length); // Logs 3
I have this HTML which is a list of elements:
<div class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
I've gotten an array, for example, which is [3,4,0,2,1] I need to sort the list in to this order.By this I mean that the third element <div class="apple-3">third-apple</div> should be the first. The second element should be the forth-apple.
How can I change it in an efficient way? This is the expected output:
<div class="container">
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
<div class="apple-0">first-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-1">second-apple</div>
</div>
jQuery can be used.
You can do this by looping through the array and appending each div by it's matched index. Try this:
var $divs = $('.container > div').detach();
[3, 4, 0, 2, 1].forEach(function(value) {
$divs.eq(value).appendTo('.container');
});
Working example
Note that if you need to support older browsers (< IE9) then you would need to replace forEach() with a standard for loop.
You can try something like this:
$("#sort").on("click", function() {
var data = [3, 4, 0, 2, 1];
var result = "";
data.forEach(function(item) {
result += $(".container").find(".apple-" + item)[0].outerHTML;
});
$(".container").html(result);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.1/jquery.min.js"></script>
<div class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
<button id="sort">Sort</button>
Simply iterate the indexes array and keep pushing the child at nth-index
var output = [];
var indexes = [3,4,0,2,1];
indexes.forEach(function(value, index){
output.push($(".container div").eq(indexes[index])[0].outerHTML);
});
console.log(output);
$(".container").html(output.join(""));
Demo
you can try:
UPDATE:
var arr = [3,4,0,2,1];
var nodes = [];
arr.forEach(funtion(value){
var node = $('.container .apple-'+value)[0];
nodes.push(node);
});
$('.container').html(nodes);
demo
Other answers with eq are good, but if you want to sort again with a different array, or the array is unsorted initially, then they would fail. Also you asked for an efficient method, using native loops instead of jquery's each gives performance benefits. So my answer to this is
$(document).ready(function () {
var inputEls = $('#awesomeContainer').find('>').get(),
$output = $('#awesomeOutput'),
order = [3,4,0,2,1],
output = [],
myValue,
newIndex,
i,
length = inputEls.length;
for (i = 0; i < length; i += 1) {
myValue = Number((inputEls[i].className || "").replace("apple-", ""));
if (myValue >= 0) {
myValue = order.indexOf(myValue);
myValue > -1 && (output[myValue] = inputEls[i].outerHTML);
}
}
$output.append(output.join(''));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<b>Input: </b>
<div id="awesomeContainer" class="container">
<div class="apple-0">first-apple</div>
<div class="apple-1">second-apple</div>
<div class="apple-2">third-apple</div>
<div class="apple-3">forth-apple</div>
<div class="apple-4">fifth-apple</div>
</div>
<br/>
<b>Sorted: </b>
<div id="awesomeOutput" class="container">
</div>
This is going to be a rather longwinded question, so please bear with me...
I have an array of about 25-30 items. They are sorted through various filters such as brand, type, material, size, etc.. How can I go about building a searchable filter. All of the ones I've seen just include a filter:query | in their filters. However I can't get mine to query my existing array.
Here is what my array looks like, only going to show 1 item to keep size down..
$scope.products = [
{
src: 'images/img/image1.jpg',
name: 'XXX-1A',
brand: 'Brand A',
material: 'dry',
size: '00',
type: 'dry pipe',
color:'red'
}];
Function for filtering (only included 1 to save space):
$scope.brandIncludes = [];
$scope.includeBrand = function(brand) {
var i = $.inArray(brand, $scope.brandIncludes);
if (i > -1) {
$scope.brandIncludes.splice(i, 1);
} else {
$scope.brandIncludes.push(brand);
}
}
$scope.brandFilter = function(products) {
if ($scope.brandIncludes.length > 0) {
if ($.inArray(products.brand, $scope.brandIncludes) < 0)
return;
}
return true;
}
This is what I am using to filter from the HTML, I am using checkboxes to select each filter:
<div class="info" ng-repeat="p in products |
filter:brandFilter |
filter:materialFilter |
filter:typeFilter |
filter:styleFilter">
</div>
My search bar mark up:
<div class="filtering">
<div class="search-sect">
<input name="dbQuery" type="text" placeholder="Search pieces" class="search-input" ng-model="query"/>
</div>
One of the filter's mark up:
<input type="checkbox" ng-click="includeStyle('adaptor')"/>Adaptor<br>
Now that you have all the code, here are some of the things I've tried that don't seem to be running right:
My Attempt:
Search bar:
<input type="text" id="query" ng-model="query"/>
Filter:
<li ng-repeat="p in products | filter:query | orderBy: orderList">
I understand that to some experienced with angular, this is a relatively easy task, but I am just learning and can't seem to wrap my head around searching a query. It's probably a simple solution that I am overlooking. This is my first Angular app and I am trying to bite off more than I can chew in order to learn more.
I appreciate all responses, thanks in advance!
As per request: CodePen
The simple built-in angular filter is not smart enough to to work with your checkbox design, so try writing a custom filter. You will need to bind the checkboxes you mentioned to variables in your scope, e.g. brandFilterIsEnabled. See the tutorial for writing custom filters. Here is a working example.
var myApp = angular.module('myApp', []);
myApp.controller('ctrl', function ($scope) {
$scope.items = [{
name:'foo',
color:'red'
},{
name:'bar',
color:'blue'
},{
name:'baz',
color:'green'
}];
$scope.searchNames = true;
$scope.searchColors = true;
$scope.$watch('searchColors', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
$scope.$watch('searchNames', function(){
$scope.searchKeys = [ $scope.searchNames ? 'name' : null, $scope.searchColors ? 'color' : null ];
});
});
myApp.filter('advancedSearch', function($filter) {
return function(data, keys, query) {
results = [];
if( !query ){
return data;
} else {
angular.forEach( data, function( obj ){
var matched = false;
angular.forEach( keys, function( key ){
if( obj[key] ){
// match values using angular's built-in filter
if ($filter('filter')([obj[key]], query).length > 0){
// don't add objects to results twice if multiple
// keys have values that match query
if( !matched ) {
results.push(obj);
}
matched = true;
}
}
});
});
}
return results;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html ng-app="myApp">
<div ng-controller="ctrl">
<input type='checkbox' ng-model='searchNames'>search names</input>
<input type='checkbox' ng-model='searchColors'>search colors</input>
<input type='text' ng-model='query'>search objects</input>
<ul>
<li ng-repeat="item in items | advancedSearch : searchKeys : query">
<span style="color:{{item.color}}">{{item.name}}</span>
</li>
</ul>
</div>
</html>
In my view I am doing this:
<div ng-repeat="item in items">
{{item.some_key}}
</div>
some_key variable has only 3 type of string output: "unsafe", "elevated" and "trace". I want to order output of items in this order: first all items which have unsafe, then "elevated" and at the end "trace" ... I can't do this in a simple orderBy filter ... How to achieve this?
Thanks for a help in advance!
Make a custom orderBy
<div ng-repeat="item in items | orderBy: statusEvent">
{{item.some_key}}
</div>
$scope.statusEvent = function(item) {
if (item.some_key == "unsafe") return 0
else if (item.some_key == "elevated") return 1
else if (item.some_key == "trace") return 2
else return 3
}
Use a custom filter
var orders = {
unsafe:0,
elevated:1,
trace:2
}
$scope.someKeyOrder = function(item){
return orders[item.some_key];
}
and use it
ng-repeat="item in items | orderBy: someKeyOrder"
Demo at http://plnkr.co/edit/4Tjsc8?p=preview
repet to display results in a input field.
Here is the data (being returned from controller scope is companycodes)
company code
abc 111
abc 10012
abc 6434
xyz 1235
xyz 33
<div ng-repeat="x in companycodes">
<h3>{{x.company}}</h3>
<input type="text" ng-name="code" ng-model=x.code>
</div>
What I am trying to do is that it lists codes under company heading i.e,
abc
111
10012
6434
xyz
1235
33
Can you please let me know how to change the ng-repeat to get the output desired.
Thanks
You can write a filter to group the data by company then repeat the code having the corresponding company
JS
myModule.filter('groupBy', function () {
return function (array, expression) {
var result = [], i = 0;
if (!angular.isArray(array)) {
return array;
}
for (; i < array.length; i += 1) {
var value = array[i][expression];
if (result.indexOf(value) === -1) {
result.push(value);
}
}
return result;
};
})
HTML:
<div data-ng-repeat="company in (companycodes | groupBy: 'company')">
<h3>{{company}}</h3>
<div data-ng-repeat="comp in companycodes | filter: {company: company}">
<input type="text" data-ng-model="comp.code">
</div>
</div>
http://plnkr.co/edit/bhQVDUVJS8Tz7yjaEPaM?p=preview