(Meteor) 'click' event doesnt get new value - meteor

I get stuck in this case:
I create a list of records in html:
{{#each data}}
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="1"></i>
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="2"></i>
...
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="10"></i>
{{/each}}
I want to everytime I click on each item, it writes "hotel-id" of that item in console log; So, in js I create:
'click .btn-edit-ota': function (event, template) {
var hid = $(event.target).data('hotel-id');
console.log(hid);
}
And it works fine, it shows '1' in the console log when I click the 1st and so on '2' with 2nd, ...
In js, I have an autorun:
Template.myTemp.onRendered(function () {
var self = this;
self.autorun(function (computation) {
... //generate my list here...
}
});
so whenever I change any checkboxs or filters or current page..., the autorun will run and I get a new list.
The problem here is when that autorun runs, and I get a new list.
e.g: now is:
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="11"></i>
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="12"></i>
...
<i class="fa fa-fw fa-pencil-square-o btn-edit-ota" data-hotel-id="20"></i>
I click in the 1st, It shows '1' in console log. :((
It should show '11'. Because the HTML now is: ...data-hotel-id="11">, not ...data-hotel-id="1"> any more.
It must be use the old data/html I think.
Something weirds happened with that 'click' event
$(event.target).data('hotel-id');
It doesnt get a new ID.
Anyone can tell me why this happened?
Many thanks.

Related

angular 9: Multiple conditions on ngClass inside a ngFor

I'm having some issues trying to print the typical star-rating widget in my page using angular. Probably there will be an easier way to show them using css but for now i wanted to do it by code.
<i *ngFor="let star of this.stars" [ngClass]="{
'score__star fas fa-star': star === 'full',
'score__star fas fa-star-half-alt': star === 'half',
'score__star far fa-star': star === 'empty'
}"></i>
this is the code of the widget and this is the content of the array of stars:
(5) ["full", "full", "half", "empty", "empty"]
i'm not sure why, chrome draws properly the first 2 but not the others. From what i have seen in the debugger there are parts of the class that are missed...
<i _ngcontent-lqd-c56="" ng-reflect-ng-class="[object Object]" class=""></i>
<i _ngcontent-lqd-c56="" ng-reflect-ng-class="[object Object]" class=""></i>
<i _ngcontent-lqd-c56="" ng-reflect-ng-class="[object Object]" class="fas fa-star-half-alt"></i>
<i _ngcontent-lqd-c56="" ng-reflect-ng-class="[object Object]" class="score__star far fa-star"></i>
<i _ngcontent-lqd-c56="" ng-reflect-ng-class="[object Object]" class="score__star far fa-star"></i>
Any idea of what i'm missing? I also tried to mix class and ngClass to split the common part of the style but i had the same problem.
Thanks a lot!
I see one workaround for this problem.
Could you change your classes, e.g:
getClasses(star) {
return {
'full' : star === 'full',
'half' : star === 'half',
'empty' : star === 'empty'
}}
Also I'm not sure If you know this but you can pass method to ngClass directive
<i *ngFor="let star of stars" [ngClass]="getClasses(star)">
{{star}}
</i>

Avoid ember to wrap my component

This is my component:
{{#link-to routeName class="list-group-item"}}
<i class="fa {{icon}} fa-fw"></i> {{text}}
{{/link-to}}
Which I use:
<div class="list-group">
{{icon-link routeName="my-account" icon="fa-user" text="Personal details"}}
...
</div>
The expected html is:
<div class="list-group">
<a class="list-group-item" href="xxx">
<i class="fa fa-user fa-fw"></i> Personal details
</a>
...
</div>
But because ember wraps the components in a div, the bootstrap rules do not apply anymore and the list-group has a wrong style.
If I change the component tag to a, and remove link-to from the component template, I loose the flexibility of link-to - and I do not know how to set attributes (href, class) in the containing tag.
It seems I can not use an Ember component for this then? Or is there a way to tellink ember no to wrap my component in a div, or anything else really: in order for the CSS to work, the markup structure must not be modified.
I've not tried this myself but apparently you can create custom link-to components by extending Ember.LinkComponent. Something like this might work...
// app/components/icon-link.js
export default Ember.LinkComponent.extend({
classNames: ["list-group-item"],
icon: null,
text: null,
})
...
// app/templates/components/icon-link.hbs
<i class="fa {{icon}} fa-fw"></i> {{text}}
...
// wherever
{{icon-link 'my-account' icon="fa-user" text="Personal details"}}
Here's a related blog post which may help you also - http://til.hashrocket.com/posts/faef1058c3-inheriting-from-linkcomponent-in-ember-is-amazing

Accessing data from outside events callback

<template name="SideNav">
<ul class='block-items white'>
{{#each blocks}}
<li class='block-item'>
<i class="fa fa-fw fa-folder"></i>
<i class="fa fa-fw fa-folder-open"></i>
<a href='#' class='block-item-link'>
{{name}}
...
{{/each blocks}}
</template>
Given this, I can access each block-item's id when it's clicked by doing
Template.SideNav.events({
"click .block-item": function (e, tem) {
//var blockItemId = this._id;
}
});
How can I borrow the same feature from other places, like onRendered()? Take a look at the following example:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
// How do I get blockId?
})
console.log("block item rearranged");
}
});
update is a callback function that's invoked when there was a change in the order of block items in the ul list. I need a way to iterate through all the block items and get their corresponding Mongo id's. How can I do it?
Related Documents:
The context of "this" in Meteor template event handlers (using Handlebars for templating)
Update: the "Meteor way"
If you are looking for how Blaze gets this data context for events and helpers, it turns out there is a magical Blaze.getData() function which takes a Blaze view or a DOM object and returns its data context. As far as I could tell by looking at the code, it seems to be the tool Blaze uses for providing data contexts to helpers and events.
So in your case, you could use:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
var context = Blaze.getData(blockItem.get(0));
var blockId = context._id;
})
console.log("block item rearranged");
}
});
Original answer
An easy way to get the id of a document when working with DOM manipulation (other than blaze events) is to explicitly set it as an attribute in your template, such as:
<template name="SideNav">
<ul class='block-items white'>
{{#each blocks}}
<li class='block-item' id='{{_id}}'>
<i class="fa fa-fw fa-folder"></i>
<i class="fa fa-fw fa-folder-open"></i>
<a href='#' class='block-item-link'>
{{name}}
...
{{/each blocks}}
</template>
This way, you can just fetch the id using jquery's attr method:
Template.SideNav.onRendered(function() {
this.$('.block-items').sortable({
update: function (e, ui) {
_.each($('.block-item'), function (blockItem) {
var blockId = blockItem.attr('id');
})
console.log("block item rearranged");
}
});

Update icon returned by CSS

In the application I am working on, we can add the following markup for the pictured result
<span class="cell-inner-undefined">
<span title='Not defined' class="status pl-undefined" ></span>
</span>
Inside the relevant CSS we have the following:
.pl-undefined:before {
content: "";
color:#969696;
}
The item assigned to content looks like unicode. Instead of that I want to get the result of the following:
<span class="fa-stack fa-5x">
<i class="fa fa-info-circle fa-stack-1x" style="color:blue" ></i>
<i class="fa fa-ban fa-stack-1x" style="color:red"></i>
</span>
How can I get the class 'pl-undefined' to return the FA icon generated above?
p.s: Adding the fa span in my page displays the desired icon, but I need it to be displayed using the class.
I didn't find any other way of achieving this, other than adding a javascript which will find a <span class="cell-inner-undefined"> and replace it with the fa CSS

How Do I Join Data From Two Collections Using Spacebars?

I have a template (tmpl1) which refers to a collection projectdetails, in the following code I can successfully show {{detailname}} what is based on the collectiondata projectdetails.detailname
But now I need to show also the Projectname which is in projects.name I do have the project._id saved in projectdetails.projectId
How can I now define a handelbar like {{projectName}} to display the project name.
I have tried to define this in projectdetails.js as helper but I was not successful. Can someone please add a code sniplet which explains how to define the handelbar and how to retrieve the data?
<template name="tmpl1">
<div id="example" class="panel">
<ol class="breadcrumb">
<li><i class="fa fa-home"></i> Start</li>
<li><i class="fa fa-cubes"></i> Projekte</li>
<li><i class="fa fa-cogs"></i> Details</li>
<li class="active">{{detailname}} {{projectName}}</li>
</ol>
</div>
You can just add a helper for projectName which joins the two collections.
The context of your template appears to be a "project detail" document, so inside of the projectName helper, this.projectId should be the id of the project document. Assuming the collection is called Projects and each project has a name field, the code should look something like this:
Template.tmpl1.helpers({
projectName: function() {
var project = Projects.findOne(this.projectId);
return project && project.name;
}
});

Resources