EmberJS view is not updating when updating an object in an array - ember.js

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);
});

Related

Cant we put a ember concurrency task in glimmer component getter, which is tracking the components arguments

-- 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?

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'));
},
}

Ember view rerenders on receiving update

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?

Don't want to use any tag(including the default div tag) in Ember.Collection View

Title may sound stupid, consider the following code
My Handlebars File
<table id="main-table">
<tr>
<td>
<h1>Some Text</h1>
</td>
{{#collection myCollectionView}}
<td>
<table>
<tr><td>{{view.someProperty}}</td></tr>
</table>
</td>
{{/collection}}
</tr>
</table>
My View File
myCollectionView = Ember.CollectionView.extend({
contentBinding: "myController.someArray",
//someArray has say 4 elements
itemViewClass: Ember.View.extend()
})
I want it to render the 4 tables inside the #main-table, it instead renders them outside the #main-table because it encloses my itemViewClass inside the default div tag. I can only change the tagName property but can't set it to nil I guess, any hack for this issue?
The JSFiddle
In response to the first answer
The problem with {{each}} is that, I am using an EditableField as follows:
(just to sound clear, editable field is the one which changes a div to textfield on double click & back to div tag on focus out, simple widget built using ember)
updated Handlebars file
<table id="main-table">
<tr>
<td>
<h1>Some Text</h1>
</td>
{{#collection myCollectionView}}
<td>
<table>
<tr><td>{{view.myEditableField valueBinding="view.content"}}</td></tr>
</table>
</td>
{{/collection}}
</tr>
</table>
updated view file
myCollectionView = Ember.CollectionView.extend({
contentBinding: "myController.someArray",
//someArray has say 4 elements
itemViewClass: Ember.View.extend({
alertFunc: function(){
alert("content did change");
}.observes('content')
})
})
I want an observer to fire whenever the value in one of the editableField is changed, so that I can update my records in database. Can we accomplish this thing using {{each}} helper? also, arrayContentDidChange will only fire if the array length changes
It is possible to do this in a Ember View
App.MyView = Ember.View.extend({
tagName: ''
});
AFAIK, there can't be Ember.View without "real presence" in the DOM, but you can use the {{each}} helper if you don't want to add a view that acts as a container (here a Ember.CollectionView).
Set tagName to null does not work, see Ember.View source code.
Template:
<script type="text/x-handlebars">
<table id="main-table">
<tr>
<td>
<h1>Some Text</h1>
</td>
{{#each App.content}}
<td>
<table><tr><td>{{name}}</td></tr></table>
</td>
{{/each}}
</tr>
</table>
</script>​
Code:
App = Ember.Application.create();
App.content = [{name: "foo"}, {name: "bar"}, {name: "baz"}];
​
See this JSFiddle.

Dynamic class binding on a nested child view in #each - how?

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']