How do you get json #attributes item in a meteor template - json

I have a json that is converted from XML and kept "#attributes" :
{"stop":"1021","route":"0057","direction":"1","departures":{"departure":[
{"#attributes":{"accurate":"1","headsign":"Rennes R"},"content":"2013-03-25T12:00:23+01:00"},
{"#attributes":{"accurate":"0","headsign":"Rennes R"},"content":"2013-03-25T12:20:00+01:00"},
{"#attributes":{"accurate":"0","headsign":"Rennes R"},"content":"2013-03-25T12:40:00+01:00"}]}},...
you can here access to the properties in javascript [1] with :
departure[0]["#attributes"].accurate
but if you want to grab it in a template with Meteor, how do you do this?
[1] JSON #attributes

I would suggest accessing the field in a function such as
Templates.your_template.attributes = function()
{
return this["#attributes"];
}
in your template
{{attributes}}

the template in the html side will look like this :
<template name="status">
<div class="line {{status}}_line">
{{stop}}
{{#each departures.departure}}
{{> attributes}}
{{/each}}
</div>
</template>
<template name="attributes">
<div class="attributes">
{{content}}
accurate : {{{access_attributes this}}}
</div>
</template>
and on the js side :
Template.attributes.access_attributes = function(context) {
return context["#attributes"].accurate
}

Related

Variable in html ,angular

I am working on an app in angular and in an html file i have something like this
<div *ngFor="let var of list">
<div>
{{newVar.name}}
<div>
</div>
My problem is that i dont know how to declare newVar properly in the div because i want newVar to be a result returned from a function in the component that takes the first var as parameter
so i basically want something like
newVar=func(var)
before using the name attribute and i dont know how to do this
I could do func(var).name but i dont only display the name so i dont want to call the function multiple times
So your workaround is something like , streaming list in html and passing var to typescript function func(var) storing result in newVar. From there you want to display name value in UI . Is my understanding is correct , my suggestion is
ts
newVar = [];
///
func() {
list.forEach(element=>{
newVar.push(element);
});
}
html
<div *ngFor="let var of newVar">
<div>
{{var.name}}
<div>
</div>
Currently there aren't any direct solution for this. One workaround is to use *ngFor as a hack (and the cost is performance)
<div *ngFor="let _var of list">
<div *ngFor="let newVar of [func(_var)]">
{{newVar.name}}
</div>
</div>
you has severals options:
<div *ngFor="let var of list">
{{func(var).name}}
</div>
Use an auxiliar array
//in your .ts
auxArray:any[]=[];
this.auxArray=this.list.map(x=>this.func(x))
//and iterate over auxArray
<div *ngFor="let var of auxArray">
{{var.name}}
</div>
//or iterate over list and use "index"
<div *ngFor="let var of list;let i=index">
{{var}} = {{auxArray[i].name}}
</div>
If your list is an array of object you can also
//in your .ts
this.list.forEach(x=>{
data:this.func(x)
}
//and iterate over list but use data.name
<div *ngFor="let var of list">
{{var.data.name}}
</div>
The first option has a poor efficency because Angular execute the function several times -each time check the application, you can see if use a console.log(var) in your function
You can pass variables to newvar function like this.
<div *ngFor="let var of list">
<div> {{newVar(var)}} <div>
</div>
i have found a solution,basically you can do something like
<div *ngIf="func(var) as newVar">
{{newVar.name}}
</div>

when using a GET method data is coming in console not in HTML

I have written my get method inside ngOnInIt(). When I am printing data in console it is visible, but when printing in HTML using interpolation, it is returning [ object object]
{{filteredCourses}} ==> [object object]
and when i am using {{course.category|json}} so here i am getting all values of array ["course" : "database" , "category" : "database" , "length" : "2hr" ] thats how the value is coming
html :-
<div class="courses" fxLayout="row wrap" fxLayoutAlign="center" [#animateStagger]="{value:'50'}">
<div class="course" *ngFor="let course of filteredCourses" fxFlex="100" fxFlex.gt-xs="50"
fxFlex.gt-sm="33" [ngClass]="course.category" [#animate]="{value:'*',params:{y:'100%'}}">
<div class="course-content" fxLayout="column" fxFlex="1 1 auto">
<div class="header" fxLayout="row" fxLayoutAlign="center center"
[ngClass]="course.category + '-bg'">
<div class="category" fxFlex>
{{course.category|json}}
</div>
</div>
</div>
Code:
filteredCourses: any[];
this.product_name = getProduct()['name'];
console.log(this.product_name);
this.token = getToken();
this.httpHeaders = new HttpHeaders({ "Authorization": "Bearer " + this.token });
this._httpClient.get('http://127.0.0.1:8000/api/products/info/'+this.product_name+'/',{headers: this.httpHeaders})
.subscribe(
data => {
this.product = data;
this.courses = data['cources'];
this.filteredCourses = this.courses;
console.log(this.filteredCourses);
},
error => {
console.log(error);
}
);
try using JSON.stringify(yourObject) or maybe in certain cases you can use Object.keys().
You need to use loop if its an array of object or you might want to print the properties of object individually.
But if you want to see the object filteredCourses in template, use json pipe.
{{filteredCourses | json}}
In case you need help to print values using *ngFor or properties, do let us know.
I suppose filteredCourses collection contains an array of objects. So you need to iterate through filteredCourses using ngFor directive to render data in the HTML template.
Like:
<ul>
<li ngFor="let item of filteredCourses">{{item.courseName}}</li>
</ul>

How can I repeat a piece of HTML multiple times without ngFor and without another #Component?

I want to repeat a piece of HTML, multiple times in my template.
But I want it to be repeated at different places on my page. This means that ngFor is not the solution as the pieces would be repeated directly one after the other.
A 'working solution' would be to define a specific #Component for my repeated HTML, and do something like that :
<p>Whatever html</p>
<my-repeated-html></my-repeated-html>
<h4>Whatever</h4>
<my-repeated-html></my-repeated-html>
But I find it overkill to create a dedicated component for doing something like that, it has no functional meaning and is only required by the HTML structure I want to set up.
Is there really nothing in ng2 template engine to allow me to define an "inner template" and use it wherever I need it in the current template?
update Angular 5
ngOutletContext was renamed to ngTemplateOutletContext
See also https://github.com/angular/angular/blob/master/CHANGELOG.md#500-beta5-2017-08-29
original
The recently added ngTemplateOutlet might be what you want
<template [ngTemplateOutlet]="templateRefExpression" [ngOutletContext]="objectExpression"></template>
It can currently be used like
<template #templateRef>
<pre>{{self | json }}</pre>
</template>
<template [ngTemplateOutlet]="templateRef"></template>
A template can also be passed to a child component to be rendered there
#Component({
selector: 'some-child',
providers: [],
template: `
<div>
<h2>Child</h2>
<template [ngTemplateOutlet]="template" ></template>
<template [ngTemplateOutlet]="template" ></template>
</div>
`,
directives: []
})
export class Child {
#ContentChild(TemplateRef) template:TemplateRef;
}
to be used like
<some-child>
<template>
<pre>{{self | json }}</pre>
</template>
</some-child>
stackblitz example
Another Plunker example
that uses data passed as
<template [ngTemplateOutlet]="..." [ngOutletContext]="templateData"
This way ngOutletContext can be used in the template like
<template let-image="image">
{{image}}
where image is a property of templateData
If $implicit is used
<template [ngTemplateOutlet]="..." [ngOutletContext]="{$implicit: templateData}"
the ngOutletContext can be used in the template like
<template let-item>
{{item}}
<campaign-channels-list (onItemSelected)="_onItemSelected($event)" [customTemplate]="customTemplate" (onDragComplete)="_onDragComplete($event)" [items]="m_blockList"></campaign-channels-list>
<template #customTemplate let-item>
<a href="#" [attr.data-block_id]="item.blockID">
<i class="fa {{item.blockFontAwesome}}"></i>
<span>{{item.blockName}}</span>
<i class="dragch fa fa-arrows-v"></i>
<span class="lengthTimer hidden-xs">
{{item.length | FormatSecondsPipe}}
</span>
</a>
</template>
and in rx component:
<div class="sortableList">
<li (click)="_onItemSelected(item, $event, i)" *ngFor="let item of m_items; let i = index" class="listItems list-group-item" [ngClass]="{'selectedItem': m_selectedIdx == i}">
<template [ngTemplateOutlet]="customTemplate" [ngOutletContext]="{$implicit: item}">
</template>
</li>
</div>
pay attention to:
[ngOutletContext]="{$implicit: item}"
as well as
<template #customTemplate let-item>

Meteor #each block issues

I would like to iterate over a Mongo query for the user's collections using the each block.
I have the following html template that should load in different pieces of data from the profile object in the users collection.
To clarify, the users Collection has a services, status and profile object
{{#each profile}}
<div class="profileUser oneDiv">
<div class="profileUserLeft">
<div class="profileUserImage">
<div class="spin"> {{> spinner}} </div>
<img src="{{profile.picturelrg}}" class="profileUserImg">
</div>
<div class="profileUserGraph">
<label for="myChart"><b>Meetup Graph</b>
<br>
<span class="profileMonth"> {{profile.month}} </span>
<br>
<canvas id="myChart"></canvas>
</label>
</div>
</div>
<div class="profileUserRight">
<div class="profileUserName">
<ul>
<li><h1>{{profile.name}}</h1></li>
<li>
<div class="circle" style="background-color: {{online.color}}"></div>
</li>
</ul>
</div>
</div>
</div>
{{/each}}
Here is my helper that sets the query
profile: function() {
return Meteor.users.find({
_id: id
});
}
Currently the page loads in no data.
When I statically query for a property however it works. This is done like so.
profimg: function() {
return Meteor.users.find({
_id: id
}).fetch()[0].profile.picturelrg;
}
How can I be more efficient and use the each block instead of statically searching for each different property utilizing the fetch() method?
each of Blaze takes an array as parameter to loop while find method return a Cursor of MongoDB. What you need to do is fetch the Cursor to return the array
profile: function() {
return Meteor.users.find({
_id: id
}).fetch();
}
However, your logic is not correct. You are finding the profile that matches with the input id, thus the function should be
profile: function() {
return Meteor.users.findOne({
_id: id
});
}
and then you can access the property without the each loop

Accessing collection index in Handlebars/Blaze #each loop

I'm messing around with a Meteor Leaderboard example. Let's say I wanted to display the index of an item inside a handlebars #each loop:
{{#each players}}
{{> player}}
{{/each}}
<template name="player">
<div class="player {{selected}}">
<span class="index">{{index}}</span>
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
Normally one would write a handlebars helper for this, but I'm having trouble figuring out how to get it working with a Meteor collection.
How would one do this? Thank you.
There is now an #index feature in Blaze:
{{#each players}}
{{> player index=#index}}
{{/each}}
<template name="player">
<div class="player {{selected}}">
<span class="index">{{index}}</span>
<span class="name">{{name}}</span>
<span class="score">{{score}}</span>
</div>
</template>
Template.player.helpers({
index() {
var data = Template.currentData();
if( data ) {
return data.index;
}
}
});
If you are just trying to show the mongo generated id just use _id
<span class="id">{{_id}}</span>
It will show the unique index id in the collection. It won't be pretty.
I may have misunderstood your question. Sorry if I did.
Adding an answer for this question. I had to put some hours figuring it out
In your client
Template.player.data = function(data){
if(type){
return Template[ 'player' ](data);
}
}
In your template
{{#each players}}
{{data this}}
{{/each}}
This will work seamlessly.
Here's how I solved this - not a perfect solution - by using the fact that Mongo typically creates indexes that increase in value.
Template.item.index = function() {
return Items.find().count() - Items.find({_id: {$lte: this._id}}).count() + 1
}
I then use this in the template like so:
{{index}}
Hope this helps!