Set parent controller property from child controller - ember.js

I have a flyers route that has a template called flyers.hbs
<div class="button-wrap">
<button {{action 'back'}}>Go Back</button>
{{#if isPrintable}}
<button {{action 'print'}} class="float-right">Print Flyer</button>
{{/if}}
</div>
{{outlet}}
In this flyers route I have view and new. New should only show the back button and view should show the back button and the print button.
So in the view controller I specified a property like so.
import Ember from 'ember';
export default Ember.Controller.extend({
isPrintable: true,
});
But obviously the parent controller for flyers does not see that property when I navigate to the view route so my print button is not showing.
What is the proper way to do this?

As I understand you'd like to have {{isPrintable}} in flyers template with value dependent of active child route.
Maybe this will work for you.
//flyers controller
import Ember from 'ember';
export default Ember.Controller.extend({
isPrintable: true,
});
//child route
import Ember from 'ember';
export default Ember.Route.extend({
parentController: Ember.computed( function() {
return this.controllerFor('flyers');
}),
setupController: function(controller, model) {
this._super(controller, model);
this.get('parentController').set('isPrintable', false);
},
deactivate: function() {
this.get('parentController').set('isPrintable', true);
}
});

Related

set alias for `model` hook

HELP
If there is a model hook in app/routes/post.js say
model() {
return this.store.query('post');
}
in template the returned promised is accessed using
{{#each model as |post|}}
...
{{/each}}
Is there any way to set alias for the model? Something like this in route or controller?
posts: alias('model')
So I can access the returned promise in the template as
{{#each posts as |post|}}
...
{{/each}}
Is this something which is already present or something that got missed from ember documentation?
you can create alias for model property in your controller,
import Controller from '#ember/controller';
import { alias } from '#ember/object/computed';
export default Controller.extend({
posts: alias('model')
})
or using setupController in your route,
export default Route.extend({
setupController(controller, model) {
controller.set('posts', model);
},
});
Reference:
alias api documentation - alias computed property
alias your model - alias-model-rule

ember - loading model data in route for power sort?

I have a very simple set up right now. I have a book model that has a name and author. I'm trying to create a simple form that will create a new book. For the author I'm using power select to load the authors from the author model. The form set up looks like this:
<form {{action "save" on="submit"}}>
{{input value=model.title placeholder="Title"}}<br>
{{#power-select class="select"
selected=model.author
options=authors
onchange=(action (mut model.author)) as |author|}}
{{author.name}}
{{/power-select}}
<input type="submit" value="Save">
</form>
However I'm having trouble setting up the route to get this working. So far no authors show up in the select, even though there are authors stored in my database. My route looks like this:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.createRecord('book');
},
actions: {
save() {
this.modelFor(this.routeName).save();
}
},
store: Ember.inject.service(),
authors: Ember.computed({
get() {
return this.get('store').findAll('author');
}
}).readOnly()
});
First of all, how should I properly load data from the author model in the route for the books/new route? Secondly, should I be doing this in the route? From what I have read, and what people have told me, loading model data should be done in the route.
Move authors property to corresponding controller.
Also you don't need to add readonly.
So in controller :
authors: Ember.computed(function(){
return this.get('store').findAll('author');
})
And for loading model in route. Yes you should load that model which is to be a resource manipulating, in route. So now you're doing it right.
1) Using Ember.RSVP.hash inside route model hook
your route file-> I assume books/new.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return Ember.RSVP.hash({
newBook : this.store.createRecord('book'),
authors : this.store.findAll('author')
});
},
actions: {
save() {
this.modelFor(this.routeName).newBook.save();
}
}
});
and inside template you can access authors by using model.authors. and title by using model.newBook.title
<form {{action "save" on="submit"}}>
{{input value=model.newBook.title placeholder="Title"}}<br>
{{#power-select class="select"
selected=model.newBook.author
options=model.authors
onchange=(action (mut model.newBook.author)) as |author|}}
{{author.name}}
{{/power-select}}
<input type="submit" value="Save">
</form>
2) Like ebrahim suggested, you can have the below code in required controller,
authors: Ember.computed(function(){
return this.store.findAll('author');
})
3)As author model data is going to be shared data model for authors,books,books.new routes. so you can keep it in service and access it from all the required routes.
authors-service.js -> In service
import Ember from 'ember';
export default Ember.Service.extend({
store:Ember.inject.service(),
authors: undefined,
init(){
this._super(...arguments);
this.get('store').findAll('author', { reload: true }).then(function(results){
this.set('authors',results); //As this is going to be Ember.enumerables, you can iterate and get the data.
});
}
});
You can access authors from authors-service.js in any where by injecting it
authorsService:Ember.inject.service(). I guess in your case, you need to create controller books/new.js for books/new.hbs template,
books/new.js -> controller file
import Ember from 'ember';
export default Ember.Controller.extend({
authorsService:Ember.inject.service(),
authors: Ember.computed.alias('authorsService.authors');
});
Inside books/new.hbs template you can access authors property.

Ember identifying current user

I'm trying to build a simple chat app using Ember CLI with a rails API backend, using simple-auth-devise. I am very new to Ember. I have the following setup:
A conversation model which has_many messages. Each message belongs_to a user.
A conversations/show route which loads a conversation and displays all messages
The problem I have is figuring out which messages were written by the current user. I can identify the current user in the route and pass this to the controller, but I'm not sure how to do something in the template which is conditional on this. Here is the code:
Route for conversations/show:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('conversation', params.conversation_id);
},
// Get the current user
setupController: function(controller, model){
this._super(controller, model);
var currentUser = this.get('session').get('currentUser');
controller.set("currentUser", currentUser);
}
});
Then in the template I want to do something like this:
{{#each message in messages}}
{{message.body}}
{{#if message.isByCurrentUser }}
Written by me!
{{/if}}
{{/each}}
I don't know how or where to define that message.isByCurrentUser method to use the currentUser variable defined in the route.
Many thanks in advance.
I would recommend you to separate message resource and let it have its own template and controller.
//messages.hbs
{{#each message in messages}}
{{render "message" message}}
{{/each}}
//message.hbs
{{message.body}}
{{#if isByCurrentUser }}
Written by me!
{{/if}}
//message controller
import Ember from 'ember';
export default Ember.Controller.extend({
currentUser: Ember.computed.alias('session.currentUser'),
isByCurrentUser: function() {
return this.get('model.creator.id') === this.get('currentUser.id');
}.property('model.creator', 'currentUser')
});
P.S: I assumed your message model has attribute named creator. change it due to your model
simple-auth injects session into controllers and routes so you don't have to set it explicitly.

Only show part of template if there exists at least one child-object

I've got a model like this:
import DS from 'ember-data';
var Post = DS.Model.extend({
title: DS.attr('string'),
downloads: DS.hasMany('download')
});
export default Post;
and would like to show the downloads-section only when there is at least 1 or more downloads in the post.
I tried introducing a computed property in the Controller but can't access the model from there.
What else can I do?
EDIT: Here's the controller showing you what I was trying to do:
import Ember from 'ember';
export default Ember.ObjectController.extend({
hasDownloads: function(){
console.log(this.get('downloads')) // <- undefined
return true
}.property('model'),
})
EDIT2: The Object-controller above has no route since it's rendered using `{{render "post"}}. This is an example-template.
<ul class="posts">
{{#with model as post}}
{{render "post"}}
{{/with}}
</ul>
That would be its route:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('post', params).then(function(posts) {
return posts.get('firstObject');
});
}
});
Directly access the property on your controller using model.downloads:
import Ember from 'ember';
export default Ember.ObjectController.extend({
hasDownloads: function(){
console.log(this.get('model.downloads'))
return true
}.property('model.#each'),
})
Depending upon which version of Ember you are using, the proxying behavior of the controller will no longer work. Also, change the property so that it is updated when downloads are added and removed.

Ember select not binding to a property in the model

If I understand the ember.js documentation correctly then I should see the models systemStatus value get populated, but I'm not:
<div class="form-group">
<label class="col-sm-2 control-label" for="name">Description</label>
<div class="col-sm-10">
{{view "select" content=statuses value=model.systemStatus }}
</div>
</div>
This is the controller:
import Ember from "ember";
export default Ember.Controller.extend({
statuses: ["Being Built", "Active","Inactive"],
selectedSystemStatus: 'Active',
actions: {
save: function() {
// this.model.set('systemStatus', this.selectedStatus);
var s = this.get('selectedSystemStatus');
this.model.save();
},
cancel: function() {
}
}
});
The model:
import DS from "ember-data";
export default DS.Model.extend({
name: DS.attr('string', {defaultValue: 'Hello'}),
systemStatus: DS.attr('string', {defaultValue: 'Active'}),
description: DS.attr('string', {defaultValue: 'Describe me'})
});
The router:
import Ember from "ember";
export default Ember.Route.extend({
model: function() {
return this.store.createRecord('software-system');
}
});
Everything works up until you try to select an option from the UI. I'm not sure what I'm doing wrong here, and would like some help.
do you have any place where you call this.store.find('my-model')? This is where the model gets populated.
The default way would be to put it into a corresponding route in the model hook:
// routes/my-model.js
export default Ember.Route.extend({
model: function() {
return this.store.find('my-model');
}
});
With this approach, your controller will wait until the model is loaded.