Accessing Custom Component Data/Methods

2019-09-06 01:22发布

I have an html file that uses a custom component. The custom component reaches out and gets data on the bind() method. So, when the component gets bound, it gets the data and sets the properties accordingly. This component also has a Save() method that, when called, should submit the object to the database.

Now, in my outer html file, I have imported this custom component. So I have the custom component and then I have a submit button (not a part of the custom component) like this:

<custom-component></custom-component>
<button click.trigger="submitCustomComponentData()"></button>

The reason I don't have the buttons in the custom component view is because that view isn't always going to have the same buttons, which then makes the component non-extendable.

The submitCustomComponentData() method basically calls the update method that is in my component VM.

Now, when when the page loads, everything runs perfect. The data gets pulled in, all of my inputs are pre-populated with the previous data (from the DB). Everything is great. However, when I call the submitCustomComponentData() method (or click the button), I get an error because the object isn't populated. It's like I'm losing the instance or something.

Here is a snippet of some important parts:

This is what my outer html file looks like. It's made up of the custom component.

<template>
    <require from="resources/components/dispatch-questions/dispatch-questions"></require>

<section class="pages au-animate">
    <div class="row" id="dispatch-questions">
        <dispatch-questions></dispatch-questions>
    </div>
</section>

</template>

And the VM for this gets injected with the dispatch-questions component like so:

constructor(private router: Router, private dq: DispatchQuestions) {
    }

It also has a click.trigger method that SHOULD call the updateDB method that is in the component. At that moment, the component (which should already have the same instance that got created on bind()) should submit that object to the DB.

But I'm getting an error because for some reason, the object is empty. The function in the component is grabbing this.myObject and submitting it to the DB. I think when I'm calling the update function from my outer VM (not the component VM) I'm losing the component's this instance. I think that's the problem..Not sure how to fix it IF that's the issue. Any help would be awesome!

I've tried to create a simple version on Gist. https://gist.run/?id=f07b2eaae9bec27acda296189585ea6c

1条回答
混吃等死
2楼-- · 2019-09-06 01:47

There's an explanation for that in the documentation.

The General Rule for Aurelia's DI Use

Everything is an application-level singleton except for those things which are classified as "components", essentially custom elements, custom attributes and view-models created through the router or composition engine. You can change the lifetime of router and composition created components through explicit configuration.

I'd recommend using EventAggregator instead of injection. This approach ensures flexibility, extensibility and prevents tight-coupling as well.

About EventAggregator: #1 Walkthrough by Dwayne Charrington, Documentation, Contact Manager Tutorial.

Here's a gist to demonstrate it with your scenario: https://gist.run/?id=f66eaa12e4183a72a7a3cc01ce3a8fb5

app.js

Let's assume that we'd like to use more than one instances of Component custom component. To achieve that, we can publish a component:save event with associated data.

import { inject } from "aurelia-framework";
import { EventAggregator } from 'aurelia-event-aggregator';

@inject(EventAggregator)
export class App {

  components = [
    { id: 1, name: 'Component #' },
    { id: 2, name: 'Component #' },
    { id: 3, name: 'Component #' }
  ];

  constructor(eventAggregator) {
    this.eventAggregator = eventAggregator;
  }

  SubmitData(opts) {
    this.eventAggregator.publish('component:save', opts);
  }

  // ...
}

component.js

Here we can subscribe to component:save events and check if we should proceed with saving. For this reason, each Component instances should have a unique identification (number, hash, uid, etc..).

Note: there's an important cleanup part in detached method, which isn't mentioned explicitly in official documentation. That's why I've listed Dwayne Charrington's blog post first.

import { inject, bindable } from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';

@inject(EventAggregator)
export class Component {

  @bindable
  id;

  object = {};

  constructor(eventAggregator) {
    this.eventAggregator = eventAggregator;
  }

  bind() {
    this.object = {
      "Name": `My name ${this.id}`,
      "Age": 21
    };

    console.log(`component ADDED: #${this.id}`);

    this.subscriber = this.eventAggregator.subscribe('component:save', data => {

      if (data.id === this.id || data.all === true) {
        this.SubmitObjectToDatabase();
        console.log(`component:save SAVED: #${this.id}`, this.object.Name);
      } else {
        console.log(`component:save PASSED: #${this.id}`);
      }

    });
  }

  SubmitObjectToDatabase() {
    console.log(`SubmitObjectToDatabase has been called: #${this.id}`);
  }

  detached() {
    // cleanup
    this.subscriber.dispose();
    console.log(`component REMOVED: #${this.id}`);
  }
}
查看更多
登录 后发表回答