Reputation: 893
I'm trying to re-render a specific component
when another component
is clicked. When the user clicks the particular button component
, a variable in sessionStorage
changes, which is used by another component
to display data. Upon click I want that specific component to re-render itself. I have seen Ember Re-render component and Ember Rerendering component within component, but they don't seem to be working in my case. Here are my files:
templates/components/buttons/button-cancel.hbs
{{#each-in metaData as |module definition|}}
{{#if (eq definition.name "cancel_button") }}
<button class={{definition.css_class}} {{action "changeToAccounts"}}> Accounts </button>
{{/if}}
{{/each-in}}
{{yield}}
components/buttons/button-cancel.js
import Component from '@ember/component';
import MD from "../../utils/metadata";
export default Component.extend({
init: function() {
this._super(...arguments);
this.metaData = MD.create().getMetaViewStuff("Leads", "record", "buttons");
// console.log(this.metaData);
},
actions: {
changeToAccounts: function() {
sessionStorage.setItem('module', "Accounts");
}
}
});
templates/components/panels/list-panel.hbs
{{buttons/button-save}} <!--This button is same as button-cancel-->
{{buttons/button-cancel}}
{{field-list-headers}}
{{yield}}
components/field-list-headers (the component that needs re-rendering)
import Component from '@ember/component';
import MD from "../utils/metadata"
export default Component.extend({
init: function(){
this._super(...arguments);
this.metaData = MD.create().getMetaViewStuff(sessionStorage.getItem('module'), "list", "panels")
}
});
function getMetaViewStuff
getMetaViewStuff: function(module, submodule, item, i18n) {
if (this.modules[module]["views"][submodule]["meta"] !== undefined && this.modules[module]["views"][submodule]["meta"][item] !== undefined) {
let meta = this.modules[module]["views"][submodule]["meta"][item];
return meta;
}
return false;
}
Upvotes: 0
Views: 1082
Reputation: 8724
My recommendation would be to share the same property via a service and to use this service to update local storage and cache the value on said service. I've provided an example that uses a service to share a value amongst two components (I couldn't use local storage in the twiddle).
So let's assume we want to show a list of programming languages either as a table or as an ordered list. We have two components, the reusable mode-changer
button for toggling the mode and the programming-languages
component for actually rendering the list, who both interact with the shared mode-service
.:
export default Ember.Service.extend({
init(){
this._super(...arguments);
//actually read from local storage here and set default on null
this.set('mode', 'list');
},
toggleMode(){
let newValue = this.get('mode') === 'list' ? 'table' : 'list';
//actually store to local storage here before caching on the service
this.set('mode', newValue);
}
});
Imagine this template showing both components:
{{programming-languages languages=languages}}
{{mode-changer}}
The mode-changer
injects the mode-service
, with which it derives the logical button text and toggle the mode-service
's mode
property via toggleMode
:
export default Ember.Component.extend({
modeService: inject(),
buttonText: computed('modeService.mode', function(){
let mode = this.get('modeService.mode');
return mode === 'list' ? "Change to table" : "Change to list";
}),
actions: {
toggleMode(){
let modeService = this.get('modeService');
modeService.toggleMode();
}
}
});
component of mode-changer
:
<button onclick={{action 'toggleMode'}}>{{buttonText}}</button>
The programming-languages
component bases it's rendering mode off of modeService.mode
via a computed property:
export default Ember.Component.extend({
modeService: inject(),
renderList: computed('modeService.mode', function(){
let mode = this.get('modeService.mode');
return mode === 'list';
})
});
so that changes to the modeService.mode
will cause the computed property to invalidate and trigger a render of the component.
{{#if renderList}}
<ol>
{{#each languages as |language|}}
<li>{{language}}</li>
{{/each}}
</ol>
{{else}}
<table>
<th>Language</th>
{{#each languages as |language|}}
<tr>{{language}}</tr>
{{/each}}
</table>
{{/if}}
In Ember, service's are singletons so such sharing is appropriate in many cases. To me, this is much better than any other solution that actually stores/retrieves references to the component itself and invokes its render function.
Upvotes: 2