How to collect sub arrays are new Arrays using `computed` method? - arrays

I have a list of arrays which contains sub arrays. how to collect those arrays and return them as new array?
here is my attempt but it does not work:
transactions: Ember.computed.map('model.cardList', function(card, index ){
return card.get('transactions');
},[]), // collecting all sub arrays but not works!!
sortedCards: Ember.computed(function(){
return this.get('model.cardList'); //length 4
}.property([])), //can i store here?
What is the correct way to collect the sub arrays from parent arrays? It is required for sorting purpose.
Thanks in advance.
Trying here, but nothing works:
Twiddle
Update
According to the twiddle, I would like to print the categoryName with fruit name(s) as a list.

If your solution at the end demands working with arrays of arrays and keeping them sorted, look at the following solution.
I have added a new field called origin to your model so that we have another field to sort by:
model(){
return {
"values" : [
{
"category" : "categoryD",
"origin": "Kongo",
"fruits" :[{"name":"banana"},{"name":"gova"}]
},
{
"category" : "categoryA",
"origin": "Italy",
"fruits" :[{"name":"apple"},{"name":"orange"}]
},
{
"category" : "categoryC",
"origin": "Marocco",
"fruits" :[{"name":"pineapple"}]
},
{
"category" : "categoryB",
"origin": "Brasil",
"fruits" :[{"name":"mongo"}]
}
]
}
}
And this is how your controller may look if you want to keep the sorting field dynamic:
import Ember from 'ember';
export default Ember.Controller.extend({
shouldSortByCategory: true,
values: Ember.computed.reads('model.values'),
valuesSortingDynamic: Ember.computed('shouldSortByCategory', function(){
return (Ember.get(this, 'shouldSortByCategory') ? ['category:asc'] : ['origin:asc'])
}),
valuesSortedDynamically: Ember.computed.sort('values', 'valuesSortingDynamic'),
actions: {
changeSortField(){
this.toggleProperty('shouldSortByCategory');
},
},
});
I do not care about sorting direction now (asc vs desc), but the field by which we sort is dynamic: category vs origin and is distinguished by the shouldSortByCategory flag.
The template looks pretty much the same:
<ul>
{{#each valuesSortedDynamically as |value|}}
<li>
{{#if shouldSortByCategory}}
<strong>{{value.category}}</strong> - {{value.origin}}
{{else}}
<strong>{{value.origin}}</strong> - {{value.category}}
{{/if}}
<ul>
{{#each value.fruits as |fruit|}}
<li>{{fruit.name}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
Adjusted twiddle is to be found here: twiddle with dynamic sorting.
UPDATE
Cumulating all fruits into a single array preserving info about the category they belong to can be achieved as follows:
arrayOfFruitsArray: Ember.computed('model.values.[]', function(){
const values = this.get('model.values');
const cumulatedfruits = Ember.A();
values.forEach((value)=>{
const category = Ember.get(value, 'category');
const fruits = Ember.get(value, 'fruits');
fruits.forEach((fruit)=>{
fruit.category = category;
cumulatedfruits.pushObject(fruit);
})
});
return cumulatedfruits;
})
Updated twiddle.

In your case you don't even have to compute sub-arrays of array.
Given the model that you load as follows (taken from your twiddle):
export default Ember.Route.extend({
model(){
return {
"values" : [
{
"category" : "category1",
"fruits" :[{"name":"banana"},{"name":"gova"}]
},
{
"category" : "category2",
"fruits" :[{"name":"apple"},{"name":"orange"}]
},
{
"category" : "category3",
"fruits" :[{"name":"pineapple"}]
},
{
"category" : "category4",
"fruits" :[{"name":"mongo"}]
}
]
}
}
});
It's enough that you iterate over your arrays in the template:
<ul>
{{#each model.values as |value|}}
<li>
{{value.category}}
<ul>
{{#each value.fruits as |fruit|}}
<li>{{fruit.name}}</li>
{{/each}}
</ul>
</li>
{{/each}}
</ul>
Here is the respective Gist. Note that the only file I touched is the template.

Related

Search function from JSON structure

I am looking for a solution to search JSON values based on the user input in the search field.
For example: if the user keys in ASD, any data that contain ASD in the Json values should display.
I found an example which works like how i wanted it to be. However, they are not using JSON structure.
Here's the code that I have followed:
App.svelte:
<script>
import Search from "./Search.svelte";
const data = [
"Metrics Server",
"Node.js",
"Virtual Machine",
"Virtual Private Server",
];
</script>
<Search autofocus {data} let:filtered>
<ul>
{#each filtered as item}
<li>{item}</li>
{/each}
</ul>
</Search>
Search.svelte
<script>
import {onMount} from "svelte";
export let autofocus = false;
export let data = [];
let input = undefined;
let value ="";
onMount(() =>{
if(autofocus) {
input.focus();
}
});
$: filtered = data.filter((item) =>
item.toLowerCase().includes(value.toLowerCase()));
</script>
<style>
ul{
list-style:none;
}
</style>
<input bind:this="{input}" type="search" bind:value />
<ul>
{#each filtered as item}
<li>{item}</li>
{/each}
</ul>
This code does not work for JSON structure such as:
{"name": "tommy, "class":"a"},
{"name": "dummy, "class":"b"} ...
It will return an error like:
item.toLowerCase is not a function
How do I implement a search function that will return me the name if the user search for "tommy"
This is how i am retrieving the Json data:
let info ="";
onMount(async () =>{
const resp = await fetch('https:xx.xxx.xxx')
info = await resp.json();
});
And the data I am getting back is in this format: [editted]
[ {
"table_schema": "x",
"table_name": "a",
"column_name": "typname",
"data_type": "name",
"character_maximum_length": null
},
{
"table_schema": "b",
"table_name": "x",
"column_name": "typnamespace",
"data_type": "oid",
"character_maximum_length": null
}]
I have edited my real JSON file. The code does works for my dummy JSON but not the real one. Any idea?
You would have to loop through each of the properties on your items and compare each of them:
first loop over the items with data.filter
get all the props of each item Object.keys(item)
check if at least one matches a condition .some
compare the key in the item to the value item[key].toLower....
$: filtered = data.filter(item =>
Object.keys(item).some(key =>
item[key].toLowerCase().includes(value.toLowerCase())
)
);
Note that this code assumes all items in your array are objects, it will fail if you have a mix between objects and strings:
[ "Tommy", { name: "Sammy" }]
Here the first element doesn't really have 'keys'. You would have to add an additional check for that first.

Firebase angular many to many relation query

I have a fairly simple json structure of groups and people and I am struggling to get/read a list of the group names for each person from firebase. This is what I tried. I spent a couple of days debugging unsuccessfully. Help much appreciated.
JSON:
{
"groups" : {
"one" : {
"members" : {
"-KLxjv9OnQB2l5Ohr-7I" : true
},
"name" : "group alpha"
},
"two" : {
"members" : {
"-KM4oXjftRZZ5DXYt4B2" : true
},
"name" : "group beta"
},
"three" : {
"members" : {
"-KM4oXjftRZZ5DXYt4B2" : true
},
"name" : "group gamma"
}
},
"persons" : {
"-KLxjv9OnQB2l5Ohr-7I" : {
"groups" : {
"one" : true
},
"personName" : "name1",
"personTitle" : "title1"
},
"-KM4oXjftRZZ5DXYt4B2" : {
"groups" : {
"two" : true
},
"personName" : "name2",
"personTitle" : "title2"
}
}
}
APP.JS:
$scope.personsGroup = function(personObj){
var baseRef = new Firebase("https://un-cms-13264.firebaseio.com/");
var personsRef = baseRef.child('persons');
var groupsRef = baseRef.child('groups');
var res=[];
for(var i=0;i<Object.keys(personObj.groups).length;i++){
var groupKey=Object.keys(personObj.groups)[i]
res.push($firebaseArray(groupsRef.child(groupKey)));
};
return res;
}
HTML:
<div class="row" ng-repeat="person in persons">
<div class="col-lg-3"></div>
<div class="col-lg-3">{{person.personName}}</div>
<div class="col-lg-3"></div>
<div class="col-lg-3 groupsList">
<ul><li ng-repeat="group in personsGroup(person)">{{group.name}}</li></ul>
</div>
</div>
The best way would be to attach $firebaseArray to a $scope variable:
var ref = new Firebase("https://un-cms-13264.firebaseio.com/").child("persons").child(some-person).child("groups");
$scope.personsGroup = $firebaseArray(ref);
// When loaded
$scope.personsGroup.$loaded(function(data) {
// can do something
}, function(error) {
// error
});
How you determine some-person is up to you. You could query the persons tree and store all the persons or store it inside an array or object.
<ul>
<li ng-repeat="(key, value) in personsGroup">{{ key }}</li>
</ul>
I would not advise personGroup(person) because $firebaseArray is an asynchronous call and I feel like it could be real jumpy. Be smart with it, you could also just get the entire persons tree in one call if you wanted:
var ref = new Firebase("https://un-cms-13264.firebaseio.com/").child("persons");
$scope.persons = $firebaseArray(ref);
And do some iterating of that.

How-To: groupBy in an ng-repeat to get count of items in group

I have a list pulled from C#. I'll call it Teams. Teams has a few properties: Team Type, and Team Members (which is a subset list).
[
{
"team": {
"teamName": "The First Team",
"teamType": 1
}
},
{
"team": {
"teamName": "The Second Team",
"teamType": 2
}
},
{
"team": {
"teamName": "The Third Team",
"teamType": 2
}
}
]
My goal:
I'd like to have an ng-repeat where it I show the team type, and how many teams of that type there are, kind of like so:
<div>
<li ng-repeat="team in teams | groupBy: teamType>
Type: {{::teamType}} -- Count: {{::numberOfTeamsOfType}}
</li>
</div>
and it might look like this:
Type: 1 -- Count: 1
Type: 2 -- Count: 2
Using the angular-filter module var myApp = angular.module("myApp", ['angular.filter']); and given the object array structure you have provided, you can do this:
<li ng-repeat="(key, value) in teams | groupBy: 'team.teamType'">
Team Type: {{value[0].team.teamType}} -- Count: {{value.length}}
</li>
jsfiddle here

Angular filter by array that contains search criteria

Does the built in Angular "filter" support filtering an array in the sense that "filter where array contains "
Such as follows:
$scope.currentFilter = "Allentown";
$scope.users = [{
name: "user1",
locations: [
{ name: "New York", ... },
{ name: "Allentown", ... },
{ name: "Anderson", ... },
]
}, ... ];
<div ng-repeat="user in users | filter : { locations: { name: currentFilter } }"></div>
In other words I'm looking to filter to only users with a "locations" array that CONTAINS a location that matches the string by name.
If not, how can I accomplish this with a custom filter?
Your code snippet works as is since Angular 1.2.13. In case you're using an older version (tested on 1.0.1) and don't need to reuse your filtering routine across controllers (in which case you should declare a proper filter), you can pass the built-in filter a predicate function :
<div ng-repeat="user in users | filter : hasLocation">{{user.name}}</div>
And write something like this :
$scope.currentFilter = "Allentown";
$scope.hasLocation = function(value, index, array) {
return value.locations.some(function(location) {
return location.name == $scope.currentFilter;
});
}
Fiddle here.

filtering the list using angularjs

See my Fiddle
I have list of books label with "comic" and "fiction" in my list.
on top I have all label and if you click on each label then books labled with that text should only be displayed.
If I get the JSON key at parent level in JSON then it works perfect.
but in this case I have label key as cid and I need to sort basic on that key.
this is my js code
function Test($scope) {
$scope.persons = [{
"s": "book1",
"cl": [{
"cn": "fiction",
"cid": 1
}]
}, {
"s": "book 2",
"cl": [{
"cn": "comic",
"cid": 2
}]
}];
}
any idea?
You can use ng-click in each tab and call a function with a value .based on that value you can filter the array to new array.
like this
<span ng-click="setTab(1)">fiction</span> |
<span ng-click="setTab(2)">comic</span> |
<span ng-click="setTab(3)">No filter</span>
and in controller
$scope.setTab = function(a) {
$scope.s=a;
//filter your array based on the value
/*if(a===1){ filter fictions} and so on */
}
see my fiddle for starting

Resources