I still can’t figure out how to implement and correctly use a component in case where you need the same form to create or edit a Post, for example? The most difficult part is still calling the right action depending on if it is a new Post (should create) or an existing one (should update). I found it to be so basic and frequent in use that it would be grateful it to be a part of the docs.
Here is Posts new
template:
#templates/posts/new.hbs
{{#post-form post=model postAction=(action "savePost")}}
<button type="submit" class="btn btn-success">Save</button>
{{/post-form}}
So here is a component template:
#templates/components/post-form.hbs
<form>
<div class="form-row">
<div class="form-group col-sm-6">
<label for="title">Title</label>
{{input type="text" class="form-control" value=post.title}}
</div>
</div>
<div class="form-row">
<div class="form-group col-sm-6">
<label for="body">Text</label>
{{textarea type="text" class="form-control" value=post.body}}
</div>
</div>
<div class="form-row">
<div class="form-group col-sm-6">
{{#power-select-multiple
options=tags
selected=selectedTags
searchField="label"
placeholder="Select some tags..."
onchange=(action "selectTag")
as |tag|
}}
{{tag.label}}
{{/power-select-multiple}}
</div>
</div>
<div class="form-row">
<div class="form-group form-check col-sm-6">
{{input type="checkbox" name="archived" checked=post.archived}}
<label class="form-check-label" for="published">Archived</label>
</div>
</div>
{{yield}}
</form>
Post form component JS file:
#components/post-form.js
import Component from '@ember/component';
export default Component.extend({
tagName: '',
submit(event) {
event.preventDefault();
this.postAction(this.get('post'));
}
});
Here is posts/new route:
# routes/posts/new.js
import Route from '@ember/routing/route';
export default Route.extend({
model() {
return this.store.createRecord('post')
},
actions: {
async savePost() {
var route = this;
let controller = this.get('controller');
let post = route.modelFor(route.routeName);
let selectedTags = controller.get('selectedTags');
post.set('tag_ids', selectedTags.mapBy('id'));
await post.save();
this.transitionTo('posts');
}
}
});
And finally, posts/new
controller:
#controllers/posts/new.js
import Controller from '@ember/controller';
import { A } from '@ember/array';
import EmberObject from '@ember/object';
export default Controller.extend({
init() {
this._super(...arguments);
this.selectedTags = [];
this.tags = this._dummyTags();
},
actions: {
selectTag(tags) {
this.set('selectedTags', A(tags));
},
savePost() {
}
},
_dummyTags() {
let foot = EmberObject.create({
id: 11,
label: 'Football'
});
let voley = EmberObject.create({
id: 12,
label: 'Voleyball'
});
let handball = EmberObject.create({
id: 13,
label: 'Handball'
});
let tags = [foot, voley, handball]
return tags;
}
});
It DOES not work, compilation errors, etc. What is wrong with all that ? What I’d like is just to reuse the same component for creating or editing a Post.