A common use case working with lists is accessing a method of the list from within a list-item. For example: a project-item has an option to delete itself from the containing list. I would like to know if the pattern I describe below for Aurelia is valid or maybe there are better solutions.
In Aurelia I have the following setup:
The containing list: (project-list.html and projectList.js)
<template>
<div class="projects">
<input value.bind="newProjectName" placeholder="New project name"/>
<project-item repeat.for="project of projects" project.bind="project"></project-item>
</div>
</template>
and the child item: (project-item and projectItem.js)
<template>
<span class="title">
${project.name} <i click.delegate="deleteProject(project)" class="icon-trash"></i>
</span>
</template>
In this case deleteProject(project)
is a member of projectList VM:
function deleteProject(project){
var index = this.projects.indexOf(project);
if (index>-1){
this.projects.splice(index,1)
}
}
Unfortunately, as I understand from this issue https://github.com/aurelia/framework/issues/311, that wil not work (anymore).
As a work-around I can bind a function on the project-item VM:
@bindable delete: Function;
and in the project-list template:
<project-item repeat.for="project of projects" project.bind="project" delete.bind="deleteProject"></project-item>
That does work, provide the bound function is a assigned property with a closure:
deleteProject = function(project : Projects.Project){
var index = this.projects.indexOf(project);
if (index>-1){
_.remove(this.projects,(v,i)=>i==index);
}
}
The closure is needed to acces the correct context (this
being the project-list). Using
function deleteProject(project)
this
would refer to the context of the project-item.
Even though this construction works and has not much overhead in plumbing, it feels to me a bit fragile:
Or maybe I'm missing an Aurelia bubbling mechanism that makes accessing a parent VM handled by the framework?
Edit after answer: Based on the answer by @Sylvain I made a GistRun that implements a skeleton list and list-item implementation with add and remove:
Aurelia Skeleton list list-item implementation
Here are a few alternatives to passing a reference to the function:
Have the child component broadcast a public event using the EventAggregator
singleton instance and have the parent component react to the event
Have the child component broadcast a private event using a private EventAggregator
instance and have the parent component react to the event
Have the child component broadcast a DOM event and bind it to the parent with delete.call
like this <project-item repeat.for="project of projects" project.bind="project" delete.call="deleteProject($even t)"></project-item>
My personal preference is the third option. It feels more like "Web Components" to me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With