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.
Related
I have a nested array of objects that looks something like this:
[
{
_Category: "Animals",
_Child: {
_Obj: [{_Title: "Monkey", _Link: "www.monkeys.com"}], [{_Title: "Monkey", _Link: "www.monkeys.com"}], etc
}
},
{
_Category: "Fruit",
_Child: {
_Obj: [{_Title: "Apple", _Link: "www.apples.com"}], [{_Title: "Pineapple", _Link: "www.pineapples.com"}], etc
}
}
]
I'm trying to append the _Title and _Link of each group into a JSX element. I've been able to render the _Categories without a problem, but the nested values are giving me a hard time.
When I go to the Elements in DevTools, I can see that there are 11 different groups for each item---which is how many array of objects there are under that particular category---but the _Titles and _Links are empty.
In the code below, I mapped through the _Category data and displayed the Categories that way. Do I have to do something similar for the _Child object---another map, maybe, or something else?
Code:
Element = ({ cats }) => {
return (
<div>
{cats
.filter((cat) => cat._Root === "Quick Links")
.map((cat) => (
<>
<div className={"colFor-" + cat._Category}>
<h5>{cat._Category}</h5>
{cat._Child._Obj.map((item) => (
<>
<a href={item._Link}>
<p>{item._Title}</p>
</a>
<br />
</>
))}
</div>
</>
))
}
</div>
)
}
Here's what cats looks like:
Update: As #Dominik pointed out, the way my obj was set up was incorrect so I changed it.
According to your sample data, cat._Child._Obj is an array and each item in it is also an array, so I think you need to flat you array first then use the map function.
const myarr = [[{_Title: "Monkey1", _Link: "www.monkeys1.com"}], [{_Title: "Monkey2", _Link: "www.monkeys1.com"}]];
const myarrFlat = myarr.flat();
myarrFlat.map(cat => console.log(cat._Title, cat._Link));
how can I use map on an array to map each item to a new JSON structure?
For example my original array looks like this:
result= [
{
"pageIndex":1,
"pageName":"home",
"cssConfiguration":"fa fa-home"
}, ...]
And I want to use .map to create a different structure for the JSON objects, for example:
modifiedResult = [
{
"id":1,
"name":"Home"
},...]
I've tried to do something like this:
result.map((resultItem) => { name: resultItem["pageName"], id:resultItem["pageIndex"]});
But it doesn't work :(
In your approach are missing the parentheses within the handler:
result.map((resultItem) => { name: resultItem["pageName"], id:resultItem["pageIndex"]});
^
You can use the function map and destructuring-assignment as follow:
let arr = [ { "pageIndex":1, "pageName":"home", "cssConfiguration":"fa fa-home" }],
result = arr.map(({pageIndex: id, pageName: name}) => ({id, name}));
console.log(result)
You can use map:
const result = arr.map(({pageIndex, pageName}) => ({id: pageIndex, name: pageName}))
An example:
let arr = [
{
"pageIndex":1,
"pageName":"home",
"cssConfiguration":"fa fa-home"
}]
const result = arr.map(({pageIndex, pageName}) => ({id: pageIndex, name: pageName}))
console.log(result)
I got the following code, I was trying to filter out "asia" object in my main object before I send to my components. But its not getting filtered.
let MainObject = [{property1: "asia", value:1},{property1: "US", value:2},{property1: "asia", value:3}]
let FilteringParameter = ["asia", "EU"]
<Calendar
events={MainObject.filter(
itemX => !FilteringParameter.includes(itemX.property1)
)}
/>
If I understand your question correctly, could you not achieve this filtering by means of the following? In the case below, this would mean that the events would only include items from MainObject that have property1: "asia" key/value pairs:
Update:
If an empty array of filter parameters are supplied, the revised answer allow all items in MainObject to be returned in filtered result:
const MainObject = [{property1: "asia", value:1},{property1: "US", value:2},{property1: "asia", value:3}];
function filterByParameters(parameters) {
return MainObject.filter(itemX => parameters.length === 0 || parameters.find(parameter => parameter === itemX.property1))
}
var events = [];
// With parameters
events = filterByParameters(["asia", "EU"]);
console.log('With parameters including "asia"', events);
// With no parameters
events = filterByParameters([]);
console.log('With no parameters', events);
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.
I'm using Angular2 and I have retrieved some data from Firebase in this way:
dataset: any;
onGetData() {
this._dataService.getAllData()
.subscribe(
data => this.dataset = JSON.stringify(data),
error => console.error(error)
);
if I print dataset I get this JSON:
{"-KE8XuCI7Vsm1jKDJIGK":{"content":"aaa","title":"bbb"},"-KE8XvM268lWhXWKg6Rx":{"content":"cccc","title":"dddd"}}
How can I print out a list made up of only the title values from this JSON array?
I'd like to have: bbb - dddd
You can only iterate over an array using ngFor. In your case you need to implement a custom pipe to iterate over keys of an object.
Something like that:
#Pipe({name: 'keyValues'})
export class KeysPipe implements PipeTransform {
transform(value, args:string[]) : any {
let keys = [];
for (let key in value) {
keys.push({key: key, value: value[key]);
}
return keys;
}
}
and use it like that:
<span *ngFor="#entry of dataset | keyValues">
Title: {{entry.value.title}}
</span>
See this question for more details:
How to display json object using *ngFor
In your view you need
<div *ngFor='#data of dataset'>
{{ data.title }} -
</div>