Updating and Deleting¶
The last two aspects of implementing the full model life-cycle are updating and deleting models.
Updating¶
Updating is basically a combination of the display of a single module, together with the form functionality of creating a new module. Because you are already familiar with the majority of concepts, the explanations will be kept to a minimum.
We will first implement updating, so create a new route and component-class:
$ ember generate route modules/edit
$ ember generate component -gc edit-module
As with the individual view route, we need to specify an explicit path for this route, to include the dynamic segment. Update the route definition in app/router.js
to the following:
this.route('edit', {path: ':mid/edit'});
Now that we have the dynamic segment, we can use that in the app/routes/modules/edit.js
to fetch the model to edit:
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ModulesEditRoute extends Route {
@service store;
model(params) {
return this.store.findRecord('module', params.mid);
}
}
Which we can then display in the app/templates/modules/edit.hbs
:
and in the actual component view app/components/edit-module
:
As you can see, for each input element, we have directly bound the property of the model to that input field. Thus when the value is changed by typing, it is automatically updated in the model – but not saved to the server.
At this point the code will actually not work, because of this line:
As you can see we set the selected
attribute by checking whether the semester
property of the module we are editing is equal to the string "WS18/19"
. By default Ember does not provide this kind of functionality, so we need to install an additional package. Stop the Ember build server and then run the following:
$ yarn ember install ember-truth-helpers
Now re-start the build server and update the app/component/edit-module.js
to handle the updating.
import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
export default class EditModuleComponent extends Component {
/**
* Services
*/
@service router;
@service store;
/**
* Untracked Properties
*/
classSpan = 'invalid-feedback';
classInput = 'is-invalid';
classLabel = 'text-danger';
/**
* Actions
*/
/**
*
* Handle update of the module, reset error messages
* @param {*} event prevent default behavior
*/
@action
updateModule(event) {
event.preventDefault();
this.errorCode = '';
this.errorName = '';
this.errorSemester = '';
this.args.model
.save()
.then((model) => {
this.router.transitionTo('modules.view', model.id);
})
.catch((response) => {
response.errors.forEach((error) => {
if (error.source.pointer == '/data/attributes/code') {
this.errorCode = error.detail;
} else if (error.source.pointer == '/data/attributes/name') {
this.errorName = error.detail;
} else if (error.source.pointer == '/data/attributes/semester') {
this.errorSemester = error.detail;
}
});
});
}
/**
*
* Handle reset of module to previouse state
* @param {*} event prevents default behavior
*/
@action
resetModule(event) {
event.preventDefault();
if (this.args.model.hasDirtyAttributes) {
this.args.model.rollbackAttributes();
}
this.router.transitionTo('modules.view', this.args.model.id);
}
/**
* Sets the semester to the param's value
* @param {String} semester value of the semester
*/
@action
setSemester(semester) {
this.args.model.semester = semester;
}
}
As you can see the code is relatively minimal. This is because we directly bound the model properties to the input fields and all we need to do is call save()
to save the update model to the server and then re-direct to the individual modules view.
Should you wish to discard the changes, there is a second action, called resetModule
. This action checks if there are any unsaved changes via the hasDirtyAttributes
property. Should there be any, they are discarded by calling the rollbackAttributes
function. In any case the user is brought back to the view page of this specific module.
All that remains to be done is to create an edit link in the app/components/view-module.hbs
:
You can now try out updating a module. Unlike creating new modules, the individual module view is immediately updated after saving. This is because the findRecord
call is smart enough to remember which models have been loaded and updating them, when they are changed.
Deleting¶
The final step is to implement the “delete” action. As a reminder, last week, we added a list of actions to the model in app/models/module.js
:
import Model, { attr, belongsTo} from '@ember-data/model';
export default class ModuleModel extends Model {
@attr code;
@attr name;
@attr semester;
@belongsTo('user') teacher;
get sections() {
return {
dates: {
title: 'Dates',
icon: 'mdi mdi-calendar-clock',
},
documents: {
title: 'Documents',
icon: 'mdi mdi-file-document-box-multiple-outline',
},
exercises: {
title: 'Exercises',
icon: 'mdi mdi-test-tube',
},
students: {
title: 'TeilnehmerInnen',
icon: 'mdi mdi-account-multiple',
},
};
}
get actions() {
return {
delete: {
icon: 'mdi mdi-delete warning',
title: 'Delete',
action: 'delete'
}
}
}
}
If you look at the list of modules, you will see that the delete action is shown, but nothing happens if you click on it. Thus update the app/components/modules/modules-list.hbs
to call an action in the “actions” area:
As you can see, here we call a dynamic action where the name is taken from what we defined in the actions
getter. We also pass the module as a parameter to the action, using the action
-helper that basically behaves like the on
-helper and listens to click
events. All we need now is a controller to handle this action:
$ yarn ember generate component-class modules/modules-list
Then add the following code to handle the delete action in app/components/modules/modules-list.js
:
import Component from '@glimmer/component';
import { action } from '@ember/object';
export default class ModulesModulesListComponent extends Component {
@action
delete(module) {
module.deleteRecord();
module.save();
}
}
Because we provided the module as a parameter to the action, when handing it, we can simply call the deleteRecord()
to delete that module. deleteRecord()
does not actually delete the record on the server side, for that we need to call save()
, it just marks the record for deletion.
You can now try this out to see that we have implemented the full model life-cycle.