I have a JSON object representing calendar dates. These are added through a CMS and I'd like to be able to filter them based on date. My schema set-up has made this more difficult than I thought. Is it possible to orderBy the day value in this JSON object or is there a filter workaround?
Here is my JSON object:
{
"_id" : ObjectId("53f252537d343a9ad862866c"),
"year" : {
"December" : [],
"November" : [],
"October" : [],
"September" : [],
"August" : [],
"July" : [
{
"day" : "21",
"title" : "Event Title",
"summary" : "Event Summary",
"description" : "oEvent Description",
"_id" : ObjectId("53f252537d343a9ad862866d")
}
],
"June" : [],
"May" : [],
"April" : [],
"March" : [],
"February" : [],
"January" : []
},
"__v" : 0
}
Here is my view which already uses a custom filter to filter by month. The orderBy is not functioning but I've left it in as a placeholder to show where I'd like to set the functionality.
<div class="calDynamic" data-ng-repeat="n in [] | range:100">
<div ng-repeat="cal in calendar[n].year | filterKey:month">
<div ng-if="cal != '' ">
<div class="calendar">
<div ng-repeat="item in cal | orderBy: 'key.day' ">
<a href="/events/{{item.day}}">
<article class="eventslist">
<div class="numberedDate">
<h3>{{item.day}}</h3>
</div>
<div class="calInfo">
<h5>{{item.title}}</h5>
<p>{{item.summary}} <a>more</a></p>
</div>
</article>
</div><!-- ng-repeat val,key -->
</div><!-- calendar -->
</div><!-- ng-if cal -->
</div><!-- ng-repeat cal -->
</div><!-- calDynamic -->
You should be able to define a custom sort function that sorts by any item in your object. The key bit is to convert the object to an array in the filter function.
Here's an example:
app.filter('orderByDayNumber', function() {
return function(items, field, reverse) {
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (a[field] > b[field] ? 1 : -1);
});
if(reverse) filtered.reverse();
return filtered;
};
});
You would then call it like this:
<div ng-repeat="(key, val) in cal | orderByDayNumber: 'day' ">
Note, you shouldn't write val.day as that is assumed.
Look at this great blog post here for more info.
EDIT: In fact, it looks like your structure is actually already an array, so while this technique will still work, it may not be necessary - it might have just been the way you were adding the parameter to orderBy that was causing issues.
Related
I'm trying to fetch data from a dd group that is not really well structured. The 'group' does have a DD wrapper but inside it's only p/div without a grouped wrapper around it:
[DD]
[P] Key
[DIV]
[P] Value
[P] Key
[DIV]
[P] Value
Is it possible to collect the data the proper way?
The html code I'm processing:
<dd class="product-specifications-v2__items">
<p class="product-specifications-v2__key">
EAN/UPC - product
</p>
<div class="product-specifications-v2__value">
<p class="product-specifications-v2__value-item">
7912372
</p>
</div>
<p class="product-specifications-v2__key">
Weight
</p>
<div class="product-specifications-v2__value">
<p class="product-specifications-v2__value-item">
2,170
<span>kg</span>
</p>
</div>
</dd>
I currently get the following result as a array:
{
"key": [
"EAN\/UPC - product",
"Weight"
],
"value": [
"7912372",
"2,170 kg",
]
}
And I need to get (without arrays):
{
"key": "EAN/UPC - product",
"value": "7912372"
},
{
"key": "Weight",
"value": "2,170 kg"
}
I'm fetching the data via an API with the following request:
{
"name":"attributes",
"selector":"div.product-specifications-v2__wrapper dl dd",
"targets":[
{
"name":"key",
"selector":"p.product-specifications-v2__key",
"dataType":"title"
},
{
"name":"value",
"selector":"div.product-specifications-v2__value p.product-specifications-v2__value-item",
"dataType":"title"
}
]
}
Using XPath 3.1 (for instance, inside the browser with Saxon-JS (https://www.saxonica.com/saxon-js/documentation2/index.html), also with Node) you can use a path expression that creates an XPath 3.1 XDM map with the key and value:
//dd[#class = 'product-specifications-v2__items']/p[#class = 'product-specifications-v2__key']!map { 'key' : normalize-space(), 'value' : following-sibling::div[#class = 'product-specifications-v2__value'][1]!normalize-space() }
const html = `<dd class="product-specifications-v2__items">
<p class="product-specifications-v2__key">
EAN/UPC - product
</p>
<div class="product-specifications-v2__value">
<p class="product-specifications-v2__value-item">
7912372
</p>
</div>
<p class="product-specifications-v2__key">
Weight
</p>
<div class="product-specifications-v2__value">
<p class="product-specifications-v2__value-item">
2,170
<span>kg</span>
</p>
</div>
</dd>`;
var htmlDoc = new DOMParser().parseFromString(html, 'text/html');
const results = SaxonJS.XPath.evaluate(`//dd[#class = 'product-specifications-v2__items']/p[#class = 'product-specifications-v2__key']!map { 'key' : normalize-space(), 'value' : following-sibling::div[#class = 'product-specifications-v2__value'][1]!normalize-space() }`, htmlDoc, { 'xpathDefaultNamespace' : 'http://www.w3.org/1999/xhtml' });
console.log(results);
<script src="https://www.saxonica.com/saxon-js/documentation2/SaxonJS/SaxonJS2.rt.js"></script>
The JavaScript API of Saxon-JS returns the sequence of XDM maps as an array of JSON objects to JavaScript.
I have a json object called blogData with json data. Inside the json obj the tags key may have multiple tag values. I would like to display the tags values separately in span tag while iterating using map function.
Now multiple tags are displaying in a single span tag ( please see below) How can I fix this ?
const blogData = [
{
"id" : 1,
"title":"Cypress tests",
"images":"/images/image1.jpg",
"description": "Add the E2E cypress UI tests",
"tags": "cypress"
},
{
"id" : 2,
"title":"Jmeter tests",
"images":"/images/image2.jpg",
"description": "Performance test using Jmeter tool",
"tags": ["jmeter", "performance"]
},
{
"id" : 3,
"title":"Basic Unix commands",
"images":"/images/image3.jpg",
"description": "Learn basic unix commands in git bash",
"tags": "unix"
},
{
"id" : 4,
"title":"Postman",
"images":"/images/image4.jpg",
"description": "Api testing using postman",
"tags": ["postman", "api"]
},
]
Home.js
const [searchResults, setSearchResults] = useState([]);
<div className="container">
{
searchResults.map(({ id, title, images, description, tags }) => (
<div key={id} className="column-center">
{/* <img className="blogImage" key={images} src={images} alt="image"></img> */}
<div className="blogtitle">
<span key={title}>{title}</span>
</div>
<section>
<p className="blogdescription" key={description}>{description}</p>
</section>
<section className="col1">
<span key={tags}>{tags}</span>
</section>
<section className="col2">
<a>Read more {'>'}{'>'}</a>
</section>
</div>
))
}
</div>
I think this what you are after.
Sandbox
<section className="col1">
{Array.isArray(tags) ? (
tags.map((tag) => (
<span style={{ marginRight: "10px" }}>{tag}</span>
))
) : (
<span>{tags}</span>
)}
</section>
You could make this code much simpler be having the tags field always be an array even if there is a single element.
I'm working on an angular 4 project calling a json through a service, everything works very well exept for a single thing, my json has the following simplified structure for understanding the problem:
{
"animals" [
{
"name" : "dog"
"subgroup": "vertebrate"
"class" : "mammal"
},
{
"name" : "pig"
"subgroup": "vertebrate"
"class" : "mammal"
},
{
"name" : "cat"
"subgroup": "vertebrate"
"class" : "mammal"
},
{
"name" : "snake"
"subgroup": "vertebrate"
"class" : "reptile"
},
{
"name" : "lizzard"
"subgroup": "vertebrate"
"class" : "reptile"
},
{
"name" : "crocodile"
"subgroup": "vertebrate"
"class" : "reptile"
},
]
}
and i want to iterate ONLY the objects with the "class" : "reptile"
i made this structure:
<div class="col-12 mb-3" *ngFor="let reptiles of animals">
<div *ngIf = "reptiles.class == reptile">
<div class="row">
<div class="col-12">
<h5 class="py-3 bg-dark text-white pl-3 mx-0 mb-3">{{reptiles.name}}</h5>
<p class="py-3 bg-dark text-white font-weight-light pl-3 m-0">{{reptiles.class}}</p>
</div>
</div>
</div>
</div>
but what happens is that it iterates three empty
<div class="col-12 mb-3" *ngFor="let reptiles of animals">
</div>
corresponding to the mammals, and i want that objects not to iterate at all, i want to iterate only the objects with the class "reptile".
how can i achieve that?
The easy fix is to use ng-container instead of a div to iterate:
<ng-container *ngFor="let reptiles of animals">
<div class="col-12 mb-3" *ngIf="reptiles.class == reptile">
<div>
<!-- ... -->
</div>
</div>
</ng-container>
Of course the template still iterates over these entries now, but it will not create any DOM node for it whatsoever (the magic of ng-container).
Possibly a better fix would be to instead filter in your component and only pass the data you want to display to the template:
// In your controller after receiving the animals data:
this.reptiles = this.animals.filter(a => a.class === "reptile");
// Template
<div *ngFor="let reptile of reptiles">...</div>
You can also write a filterBy pipe or take one from an existing library such as ngx-pipes. But beware that Angular discourages that as it easily becomes a performance pitfall.
I think that you can use this solution
Just filter by class property:
filterItemsOfType(type){
return this.items.filter(x => x.class == type);
}
Cheers,
#carlosrojas_o
you just need to filter your data in component like this:
this.filteredAnimals = this.animals.filter(animal => animal.class === "reptile"); // now use filteredAnimals in html template
Hope it will help
I have list of schools each with a code for a school level instead of ES, MS, HM.
[
{
"nameOfInstitution": "Summer Elementary",
"schoolLevel": "01304"
},
{
"nameOfInstitution": "Grady Middle",
"schoolLevel": "02400"
}
]
I am planning to use another JSON to get the description of those codes from:
{
"schoolLevel": [
{"01302": "All levels"},
{"01304": "Elementary"},
{"02400": "Middle"},
{"02402": "High school"}
]
}
What is the proper way to display this in Angular in a view where it would look like?
<div class="item item-text-wrap">
<p ng-repeat="school in schools">{{school.nameOfInstitution}} - {{school.schoolLevel}}</p>
</div>
Should it 1). iterate through the main JSON and insert the description after "schoolLevel" or 2). should I use a look-up method to find out the description each time I display a school?
I would think the first option is the better choice, but can anyone share some snippets of code on how to best achieve that?
Thank you!
You can create a filter for lookup:-
DATA:-
$scope.schools=[
{
"nameOfInstitution": "Summer Elementary",
"schoolLevel": "01304"
},
{
"nameOfInstitution": "Grady Middle",
"schoolLevel": "02400"
}
];
$scope.schoollevel={
"schoolLevel": [
{"01302": "All levels"},
{"01304": "Elementary"},
{"02400": "Middle"},
{"02402": "High school"}
]
}
Filter:-
app.filter('level',function(){
return function(item,filter){
//console.log(item.schoolLevel);
var levelVal;
item.schoolLevel.forEach(function(level){
if(typeof level[filter]!='undefined'){
console.log(level[filter]);
levelVal=level[filter];
}
}
);
return levelVal;
}
});
HTML:-
<p ng-repeat="school in schools">{{school.nameOfInstitution}} -
{{schoollevel|level:school.schoolLevel }}</p>
Plunker
Below code should work
Markup
<div class="item item-text-wrap">
<p ng-repeat="school in schools">{{school.nameOfInstitution}} -
{{level.schoolLevel | filter: school.schoolLevel : true }}</p>
</div>
Code
$scope.level = {
"schoolLevel": [
{"01302": "All levels"},
{"01304": "Elementary"},
{"02400": "Middle"},
{"02402": "High school"}
]
}
I am new in kendo ui. I have a shopping cart system like this http://demos.kendoui.com/sushi/. I want to show multiple images in a single line by creating image array. the code of this demo site at this address. https://github.com/telerik/kendo-mobile-sushi.
If you have modified menu.js and the entries look like:
{
"id" : 1,
"name" : "Sashimi salad",
"price" : 12.00,
"image" : "sashimi-salad.jpg",
"category" : "Cold starters",
"description": "Organic greens topped with market fresh sashimi, wasabi soy vinaigrette.",
"featured" : true
},
{
"id" : 2,
"name" : "Chirashi sushi",
"price" : 21.00,
"image" : [ "chirashi-sushi.jpg", "chirashi-sushi.jpg", "chirashi-sushi.jpg"],
"category" : "Cold starters",
"description": "Sushi bar variety with sushi rice.",
"featured" : false
},
Where you have entries as Sashimi salad that only have one image defined as a string and entries as Chirashi sushi where have multiple images defined in an array.
Then you should modify your templates for checking if image is a string and if not then iterate on the array elements. Something like:
<script id="menuTemplate" type="text/x-kendo-template">
<a data-role="button"
data-click="addToCartFromList"
data-item-id="#:id#"
href="\\#">#:kendo.toString(price, "c")#</a>
<a class="details-link" data-role="listview-link" href="\#details?id=#:id#">
# if (typeof image === 'string') { #
<img src="content/images/75/#= image #"/>
# } else { #
# for (var i = 0; i < image.length; i ++) { #
<img src="content/images/75/#= image[i] #"/>
# } #
# } #
<h2>#:name#</h2>
<span class="added"#= cartDataSource.get(id) ? "" : 'style="display: none"' #>Item added to cart</span>
</a>
</script>