I'm creating a real time app in Ember.
Every time I receive an update I do the following:
record = serializer.extractSingle(store, type, data);
store.update(socketModel, record);
The update is an drawnNumbers array.
This happens in my view;
{{#each bingoCard in ownBingoCards}}
<div class="col-sm-4">
<div class="table-responsive">
<span class="label label-primary">Card {{bingoCard.id}}</span>
<table class="table table-bordered table-card">
<tbody>
{{#each row in bingoCard.squares}}
<tr>
{{#each number in row itemController='number'}}
{{#if number}}
<td {{bind-attr class='isActive:active'}}>{{number.model}}</td>
{{else}}
<td>X</td>
{{/if}}
{{/each}}
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
{{/each}}
ownBingoCards is a computed property
ownBingoCards: function () {
var gameId, userId;
gameId = this.get('id');
userId = this.get('session.content.id');
return this.get('store').filter('bingoCard', function (bingoCard) {
return (bingoCard.get('game.id') === gameId && bingoCard.get('user.id') === userId);
});
}.property('model.bingoCards', 'session.content'),
So everytime a number gets added to the drawnNumbers array it's setting that td to active.
The only problem is, my whole view rerenders make it very laggy. But as soon as I refresh my browser it stops rerendering the whole view and just marking the numbers active. Why does this happen? Why is this refresh needed?
Related
-- when an ember concurrency task is called glimmer components getter then it runs in infinite loop.
import Component from '#glimmer/component';
import { tracked } from '#glimmer/tracking';
import { inject as service } from '#ember/service';
import { task } from 'ember-concurrency';
export default class UserTableComponent extends Component {
#service store;
#tracked users;
get taskStatus() {
let params = {
'account_id':this.args.account,
'page':this.args.page
}
this.getUsersTask.perform(params);
}
#task(function*(params) {
let recordsWithMeta = yield this.store.query('user', params);
this.users= recordsWithMeta.toArray();
}) getUsersTask;
}
user-table.hbs
<table>
<thead>
<tr>
<th>
<div class="first">Name</div>
</th>
</tr>
</thead>
<tbody>
{{#if this.taskStatus.isRunning}}
<tr>
<td >
<div class="h-64">
{{ui-kit/loader}}
</div>
</td>
</tr>
{{else}}
{{#each #users as |user|}}
{{/each}}
{{/if}}
</tbody>
</table>
Above component is called somewhere in template and passing account and page dynamic.
<UserTable
#account={{this.account}}
#page={{this.page}}
>
</UserTable>
Note: it runs in infinite loop.
I've found two things to change. But not sure if they will be enough to make it work.
First point,
{{#each #users as |user|}} is equivalent to this.args.users. But users array is defined on the component. So it has to be changed to {{#each this.users as |user|}}
Second point,
taskStatus is not returning anything. So {{#if this.taskStatus.isRunning}} will be false every time. The correct check would be {{#if this.getUsersTask.isRunning}}, because isRunning is a property of the task.
But when you changed to {{#if this.getUsersTask.isRunning}}, it will not work since no one triggering getUserTask. I think you can initiate that task in one of lifecycle hooks (such as didInsertElement).
How to use set new value to an array object for Emberjs view?
So I have a table of my data; then when I click edit button I want to change the class of the parent <tr> of that button.
So I have this inside my view.
{{#each model as |lineItem index|}}
<tr class="{{ tableRowIndex[index] }}">
<td>
<ul class="dropdown-menu pull-right">
<li>
<a href="#"
{{ action 'editLineItem' this index }} >
Edit
</a>
</li>
</ul>
</td>
</tr>
{{/each}}
This is my controller
tableRowIndex: computed(function(){
let array = [];
this.get('model').forEach(function(){
array.push("");
});
return array;
}),
actions: {
editLineItem(button,index) {
console.log(this.get('tableRowIndex'));
this.set('tableRowIndex[index]','editing-row');
console.log(this.get('tableRowIndex'));
},
}
But it didn't work out so
console.log(this.get('tableRowIndex'));
Output the same result before and after I ran
this.set('tableRowIndex[index]','editing-row');
So how can I make this things work out?
If you wish to set computed property then consider defining it with get and set function.( refer ).
In your case,you just introduce tableRowIndex and initialize it based on model property in setupController hook of route
setupController(controller,model){
this._super(...arguments);
let array = [];
this.get('model').forEach(function(){
array.push("");
});
controller.set('tableRowIndex',array);
}
and in controller.js,
actions: {
editLineItem(button,index) {
console.log(this.get('tableRowIndex'));
this.get('tableRowIndex').objectAt(index,'editing-row')
console.log(this.get('tableRowIndex'));
},
}
I have a handlebars template where i have a table.
<script type="text/x-handlebars" data-template-name="customers">
<table>
<tbody>
{{#each nomday in allnominationdays}}
<tr class="nomdays" {{action "saveNomDay" nomday on="focusOut"}}>
<td>{{nomday.confirmedVolume}}</td>
<td>{{nomday.variance}}</td>
</tr>
{{/each}}
</tbody>
</table>
</script>
In my controller i have a function which i call from the action saveNomDay defined on the tr.
update: function()
{
console.log('Not Working');
allnominationdays = this.get('allnominationdays');
//this.set('allnominationdays',null);
allnominationdays.objectAt(0).variance = 75;
this.set('allnominationdays',allnominationdays);
},
But my view is not changing when i change the value of the object array. If i set the object array to null the template updates and shows no table. I am not sure what is breaking the binding for the view to update?
the code block updates the view when in a controller function but not when called on a action. But inside the action setting the array of object to null update the view and removes the entire table. Don't know what is going on. New in EmberJS
THanks,
I am too late but better late than never. This is happening because the view is getting rendered before the update in the value can propogate to the screen. Do something like the following code :
--template
{{#if isVisible}}
<table>
<tbody>
{{#each nomday in allnominationdays}}
<tr class="nomdays" {{action "saveNomDay" nomday on="focusOut"}}>
<td>{{nomday.confirmedVolume}}</td>
<td>{{nomday.variance}}</td>
</tr>
{{/each}}
</tbody>
</table>
{{/if}}
--component / controller
self.set('isVisible',false);
var propgationPromise = new Promise(function(resolve, reject) {
//update Value
console.log("promise started");
resolve();
});
propgationPromise.then(function(){
console.log("promise stopped");
self.set('isVisible', true);
});
Iam having a table using bootstrap components with each row clickable
am also using handlebars inside table rows
<tbody data-link="row" class="rowlink">
{{#each model.pastreqlist}}
{{#if_eq {{status}} "PENDING"}}
<tr data-toggle="modal" data-target="#pastreq {{action "selectRow" this target="view"}}">
{{else}}
<tr>
{{/if_eq}}
<td>{{employee_name}}</td>
<td>{{type_id}}</td>
<td>{{from_date}}</td>
</tr>
{{/each}}
</tbody>
i want to enable the content inside tr i.e i want to pop up modal for only those rows which is having status as "PENDING"
so far i have tried this but its not working
here's my helper code also
Handlebars.registerHelper('if_eq', function(a, b, opts) {
if(a == b)
return opts.fn(this);
else
return opts.inverse(this);
});
here is my controller code
App.LinksController = Ember.ObjectController.extend({
actions: {
myleavesinfolist: function () {
rdata = $.ajax({
type: "POST",
url: "/myleaves",
dataType: "json",
async: false
}).responseJSON;
this.transitionToRoute("myleaves", rdata);
} //myleavesinfolist
} //actions
}); //controller
please help am a newbie to handlebars and ember js
i used handlebars registerhelper in my script as below
Ember.Handlebars.registerHelper('ifeq', function(a, b, options) {
return Ember.Handlebars.bind.call(options.contexts[0], a, options, true, function(result) {
return result === b;
});
});
and in my template i have done like this
{{#each model.pastreqlist}}
{{#ifeq status "PENDING"}}
<tr data-toggle="modal" data-target="#pastrequestsmodal" {{action "selectRow" this target="view"}} style="cursor: pointer">
{{else}}
<tr>
{{/ifeq}}
You should set up a computer property on your model, like this:
App.Request = Ember.Model.extend({
stats:DS.attr('string'),
isPending:function(){
if(this.get('status') === 'PENDING'){
return true;
}
}.property('status')
});
Then in your template, you can do it like this:
<tbody data-link="row" class="rowlink">
{{#each model.pastreqlist}}
{{#if isPending}}
<tr data-toggle="modal" data-target="#pastreq" {{action "selectRow" this target="view"}}>
{{else}}
<tr>
{{/if}}
<td>{{employee_name}}</td>
<td>{{type_id}}</td>
<td>{{from_date}}</td>
</tr>
{{/each}}
</tbody>
I had a single view with an each helper similar to this:
<table class="select-sect" cellspacing="0">
{{#each sections}}
<tr {{bindAttr class="highlight:highlight"}} {{action "selectSection" }}>
<td class="key">
{{#each zones}}
<em {{bindAttr style="color"}}> </em>
{{/each}}
</td>
<td class="sect">{{name}}</td>
<td class="price">{{currency lowPrice}} - {{currency highPrice}}</td>
</tr>
{{/each}}
</table>
Binding a dynamic class like this worked very well. If I set section.highlight == true in a controller, the view would update with the appropriate class.
"Calling" code:
zone.section.set('highlight', true);
Because I need to handle some other events on each row, I've migrated the entire table row to a nested view. I'm searching for a way to make the dynamic class work as it used to.
{{#each sections}}
{{#view SYOS.SelectSectionRowView sectionBinding="this" }}
<td class="key">
{{#each section.zones}}
<em {{bindAttr style="color"}}> </em>
{{/each}}
</td>
<td class="sect">{{section.name}}</td>
<td class="price">{{currency section.lowPrice}} - {{currency section.highPrice}}</td>
{{/view}}
{{/each}}
I don't think I can use the same bindAttr solution since it would need to apply to the #view helper. I've also tried classNameBindings & classBinding to no avail. Updating section.highlight no longer triggers this view to apply the dynamic class.
View w/ classNameBindings:
SYOS.SelectSectionRowView = Em.View.extend({
tagName: 'tr',
classNameBindings: ['isHighlighted:highlight'],
isHighlighted: function () {
return this.section.highlight;
} //also tried .property('section')
});
View with classBinding:
{{#view SYOS.SelectSectionRowView sectionBinding="this" classBinding="needsHighlight"}}
in view class:
needsHighlight: function () {
if (this.section.highlight) {
return 'highlight';
}
return '';
} .property('section'),
Neither of these seems to do the trick. Can anyone lend any insight into how to get a scenario like this going?
Thanks much!
try classNameBindings: ['section.highlight:highlight']