Angularjs displaying ng-repeat results under a field - javascript

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

Related

Search for String in Object

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.

Angularjs search product by price (from price to price)

I'm trying to add filter for searching the product by from price to price. I have following array in json format as $scope.products in the controller.
[
{"product_id":"1","product_price":"185"},
{"product_id":"2","product_price":"45"},
{"product_id":"3","product_price":"123"},
{"product_id":"4","product_price":"23"},
{"product_id":"5","product_price":"776"}
]
And below is the loop in html
<ul class="items">
<li ng-repeat="product in products | filter:{product_name: findname} | sizeFilter:(size_arr|filter:{on:true})" >
<strong>{{product.product_name | CapsFirst}}</strong>
<strong>({{product.product_category}})</strong>
<strong>({{product.product_size}})</strong>
<strong>({{product.product_color}})</strong>
</li>
</ul>
In the view I want to add two input fields for searching the products by price.
<input type="number" ng-model="from_price" />
<input type="number" ng-model="to_price" />
Can anyone guide me that I can develop in proper way. I've searched about it but couldn't found a tutorial, I'm not expertise in angularjs. Thank You...
Here's an example on plunkr of what you've been asking for. I have added a product name in order to distinguish them, try it.
https://plnkr.co/edit/NKos4x9eeB5dZQaypurg?p=preview
app.filter('sizeFilter', [function() {
return function(values, config) {
if (config.enabled) {
var filterResult = [];
angular.forEach(values, function(value) {
if (value.product_price >= config.from_price && value.product_price <= config.to_price) {
filterResult.push(value);
};
});
return filterResult;
}
return values;
}
}]);
In HTML
<li ng-repeat="product in products |rangePrice:
{'toPrice':to_price,'fromPrice':from_price}">
In JavaScript
app.filter('rangePrice', function() {
return function( items, rangePrice ) {
var filteredValue= [];
var toPrice= parseInt(rangePrice.toPrice);
var fromPrice= parseInt(rangePrice.fromPrice);
angular.forEach(items, function(item) {
if( item.product_price>= toPrice&& item.product_price<= toPrice) {
filteredValue.push(item);
}
});
return filteredValue;
};
});

Angular dynamic selects have items that affect one another

I'm attempting to make a dynamic form in Angular 1.4.7 in which:
There are multiple reports (vm.reports = [];)
Each report can be assigned ONE report object via vm.reportOptions.
Each vm.reportOptions can only be selected ONCE across multiple reports, which is filtered via exclude.
Each report supports MANY dimension objects via vm.dimensionOptions.
Each dimension can only be selected ONCE per report, which is filtered via excludeDimensions (subsequent reports have access to all the dimensionOptions and filter on their own).
These requirements are all working (roughly) with the exception of:
If I add two reports, and add the exact same dimensions (ie: Report One > Dimension One > Enable Dimension Filter and Report Two > Dimension One > Enable Dimension Filter) for each of the reports, changing the select inside of Enable Dimensions Filter changes it in both the reports.
I assume that this is happening due to the fact that I'm pushing the actual dimension objects in to each reports dimensions: [] array and that they are still pointing to the same object.
-- EDITS --
I realize angular.clone() is a good way to break this reference, but the <select> code I wrote is automatically piping in the object to the model. I was tempted to give each report their own controller and giving each report their own copy() of the options.
Would this work? Or is there a better way?
I have a working JSBin here.
Pertinent Code:
HTML:
<body ng-app="app">
<div ng-controller="AlertsController as alerts">
<pre>{{alerts.output(alerts.reports)}}</pre>
<div class="container">
<div
ng-repeat="report in alerts.reports"
class="report"
>
<button
ng-if="$index !== 0"
ng-click="alerts.removeItem(alerts.reports,report)"
>Delete Report</button>
<label>Select Report</label>
<select
ng-model="alerts.reports[$index].report"
ng-init="report"
ng-options="reportSelect.niceName for reportSelect in alerts.reportOptions | exclude:'report':alerts.reports:report"
></select>
<div
ng-repeat="dimension in report.dimensions"
class="condition"
>
<div class="select">
<h1 ng-if="$index === 0">IF</h1>
<h1 ng-if="$index !== 0">AND</h1>
<select
ng-model="report.dimensions[$index]"
ng-change="alerts.checkThing(report.dimensions,dimension)"
ng-init="dimension"
ng-options="dimensionOption.niceName for dimensionOption in alerts.dimensionOptions | excludeDimensions:report.dimensions:dimension"
>
<option value="123">Select Option</option>
</select>
<button
class="delete"
ng-if="$index !== 0"
ng-click="alerts.removeItem(report.dimensions,dimension)"
>Delete</button>
</div>
<input type="checkbox" ng-model="dimension.filtered" id="filter-{{$index}}">
<label class="filter-label" for="filter-{{$index}}">Enable Dimension Filter</label>
<div ng-if="dimension.filtered">
<select
ng-model="dimension.operator"
ng-options="operator for operator in alerts.operatorOptions">
</select>
<input
ng-model="dimension.filterValue"
placeholder="Text"
></input>
</div>
</div>
<button
ng-click="alerts.addDimension(report)"
ng-if="report.dimensions.length < alerts.dimensionOptions.length"
>Add dimension</button>
</div>
<button
ng-if="alerts.reports.length < alerts.reportOptions.length"
ng-click="alerts.addReport()"
>Add report</button>
<!--
<div ng-repeat="sel in alerts.select">
<select ng-model="alerts.select[$index]" ng-init="sel"
ng-options="thing.name for thing in alerts.things | exclude:alerts.select:sel"></select>
</div>
-->
</div><!-- container -->
</div>
</body>
JS:
var app = angular.module('app', []);
app.controller('AlertsController', function(){
var vm = this;
vm.reportOptions = [
{id: 1, niceName: 'Report One'},
{id: 2, niceName: 'Report Two'},
{id: 3, niceName: 'Report Three'},
];
vm.dimensionOptions = [
{id: 1, niceName: 'Dimension One'},
{id: 2, niceName: 'Dimension Two'},
{id: 3, niceName: 'Dimension Three'},
];
vm.operatorOptions = [
'>',
'>=',
'<',
'<=',
'=',
'!='
];
////// DEBUG STUFF //////
vm.output = function(value) {
return JSON.stringify(value, undefined, 4);
}
////////////////////////
vm.reports = [];
vm.addReport = function() {
vm.reports.push({report: {id: null}, dimensions: []});
}
vm.removeItem = function(array,item) {
if(array && item) {
var index = array.indexOf(item);
if(index > -1) {
array.splice(index,1);
}
}
}
vm.addDimension = function(report) {
console.log('addDimension',report);
if(report) {
report.dimensions.push({})
}
};
// init
if(vm.reports.length === 0) {
vm.reports.push({report: {}, dimensions: [{}]});
// vm.reports.push({report: vm.reportOptions[0], dimensions: [vm.dimensionOptions[0]]});
}
});
app.filter('excludeDimensions', [function() {
return function(input,select,selection) {
// console.log('ed',input,select,selection);
var newInput = [];
for(var i = 0; i < input.length; i++){
var addToArray=true;
for(var j=0;j<select.length;j++){
if(select[j].id===input[i].id){
addToArray=false;
}
}
if(addToArray || input[i].id === selection.id){
newInput.push(input[i]);
}
}
return newInput;
}
}]);
app.filter('exclude', [function () {
return function(input,type,select,selection){
var newInput = [];
for(var i = 0; i < input.length; i++){
var addToArray=true;
for(var j=0;j<select.length;j++){
if(select[j][type].id===input[i].id){
addToArray=false;
}
}
if(addToArray || input[i].id === selection[type].id){
newInput.push(input[i]);
}
}
return newInput;
};
}]);
How do I get around pushing same object reference to array
Use angular.copy()
array.push(angular.copy(vm.formObject));
// clear object to use again in form
vm.formObject={};
I ended up using select as so that it just set an id on the object instead of pointing to the original object. This solved the problem.

Using AngularJS to create an instant search by querying an array

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>

Finding item of array base on the ng-repeater index in Angular

In my application i have 2 array of object.layout array is for creating twitter bootstrap layout.this array is like below :
$scope.layout = [
{c:[{size:12}]},
{c:[{size:2},{size:3},{size:4},{size:3}]},
{c:[{size:3},{size:5},{size:4}]}
];
you can see how this array work in this jsbin.the other array is items array and this array is like below:
$scope.items =[
{row:1,column:0,names:['Jack','Daniel']},
{row:3,column:3,names:['Eli','Bill']},
{row:2,column:1,names:['Fred','David']}
];
and this is the repeater that i used :
<div ng-repeat="(ri,r) in layout" class="row">
<div ng-repeat="(ci,c) in r.c" class="col-md-{{c.size}} col-sm-{{c.size}} col-xs-{{c.size}} col-lg-{{c.size}} bi"> Row{{ri}}-Column{{ci}}
//Maybe other repeater come here
</div>
</div>
now i want when i want to display Jack , Daniel in row 1 column 0 and this 1 and 0 is r and c in repeater of first and second repeater.so when the repeater create row 2 column 1 also repeat on $scop.item and find the related names. but i don't know how to find items in $scope.item.and this is my jsbin
You can do something like this:
<div ng-repeat="(ri,r) in layout" class="row">
<div ng-repeat="(ci,c) in r.c" class="col-md-{{c.size}} col-sm-{{c.size}} col-xs-{{c.size}} col-lg-{{c.size}} bi">
{{getNames(ri, ci)}}
</div>
</div>
Where getNames is defined in controller:
$scope.getNames = function(r, c) {
var items = $scope.items;
for (var i = 0; i < items.length; i++) {
if (items[i].row == r && items[i].column == c) {
return items[i].names;
}
}
return '';
};
Demo: http://jsbin.com/sumuwigo/1/edit

Categories