13

I am using Aurelia's Custom Elements to repeat over a set of entries. Here is the sample gist: https://gist.run/?id=38aee854447122f021bc05e1e0de25ae

Now, I need to access the deleteEntry(entry) method when clicked on the button defined in custom element. I tried using $parent.deleteEntry(entry) but it's not working.

Saw this issue, but it's more than an year old and I am wondering if there is a cleaner way to achieve this now.

Community
  • 1
  • 1
software_writer
  • 3,941
  • 9
  • 38
  • 64
  • 1
    Couple posts that might be helpful [here](http://stackoverflow.com/questions/36813465/passing-the-parent-when-parent-is-the-same-component-type-in-aurelia/36875154#36875154) and [here](http://stackoverflow.com/questions/32777303/custom-elements-binding-context-what-is-it-exactly-how-to-access-parent-vm/32781324#32781324) – Jeremy Danyow Dec 30 '16 at 10:55

2 Answers2

21

Why not use the call binding to accomplish this?

Here's an example: https://gist.run?id=3cc553ea3bd7ed1862d87d8dbe4f5f84

app.html

<template>
    <require from="./entry"></require>

        <h2 class='text-center'>Journal Entries</h2>

        <div>
            <entry repeat.for='entry of entries' entry.bind='entry' delete-function.call="deleteEntry(entry)"></entry>
        </div>

</template>

app.js

export class App {

    entries = [{
          'date': 'Jan 1',
          'note': 'Hello World'
        }, {
          'date': 'Jan 2',
          'note': 'Good Morning'
        }];


    deleteEntry(entry) {
        console.log("Deleting entry");
        console.log(entry);

        const index = this.entries.indexOf(entry);

        this.entries.splice(index, 1);
    }
}

entry.html

<template>
  <div>${entry.date} <button click.trigger='delete()'>X</button></div>

  <div>${entry.note}</div>

</template>

entry.js

import {bindable} from 'aurelia-framework';

export class EntryCustomElement {
    @bindable entry;
    @bindable deleteFunction;

    delete() {
      this.deleteFunction();
    }

}

Obviously in a real implementation, you'll need to make sure that what is bound to deleteFunction is actually a function before trying to call it.

Ashley Grant
  • 10,879
  • 24
  • 36
  • Thanks for the working answer. That helps. However, I have many more functions in the `app.js` viewmodel such as `add()`, `edit()`, `read()`, and so on. Will I have to add a `call` binding to each of them? – software_writer Dec 30 '16 at 18:42
  • I would rethink your design at that point. Your component is way too tightly coupled to your parent component is what I'd say at the point where you're directly calling that many parents methods. You might look at using custom events. – Ashley Grant Dec 30 '16 at 18:47
  • I see. Do you mean [surrogate behaviors](http://aurelia.io/hub.html#/doc/article/aurelia/templating/latest/templating-custom-elements/5) when you say `custom events`? That's what popped up first when I searched the docs for `custom events`. – software_writer Dec 30 '16 at 18:53
  • As for the design, isn't this a valid use case? I have a collection in the parent viewmodel, and I want to use `custom element` to loop over it. But to add the `CRUD` functionality, I need to access the parent collection, as the `custom element's` viewmodel doesn't know anything about the collection. Does that make sense? – software_writer Dec 30 '16 at 18:55
  • Your custom element does not need to access the parent collection. Your custom element simply needs to fire an event and the parent can subscribe to the event using `trigger` or `delegate`. Here's info on custom events: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events Surrogate behaviors are something unrelated to this. – Ashley Grant Jan 01 '17 at 20:10
  • If you do decide to tightly couple the child custom element to the parent view model, then you are saying that you will never want to use this custom element anywhere else, as it is tied directly to the implementation of the parent view model. – Ashley Grant Jan 01 '17 at 20:10
  • That makes total sense. Thanks for the explanation. Can I use Aurelia's `EventAggregator` instead of `custom events`? – software_writer Jan 01 '17 at 20:16
  • You could, it just depends on how much you want your custom element to imitate a standard DOM element. – Ashley Grant Jan 01 '17 at 20:28
6

Using bind life cycle event you can get parent View modal in Aurelia.

bind(bindingContext, overrideContext) {
        this.parent = bindingContext;
    }

Now you can access all the variables and methods from parent view to your view.

Like below code in child view

this.parent.parentmethod();
Rayudu
  • 1,806
  • 1
  • 14
  • 31
  • Yah, I had to jump through a few extra hoops `overrideContext.parentOverrideContext.bindingContext` - not sure why, but this answer definitely got me on the correct path – Tjad Clark Apr 28 '18 at 22:47
  • I have got needed parent through `bindingContext.router.container.viewModel` – Eugene Mala May 18 '19 at 17:10