Aurelia: accessing Custom Element's custom functions or custom attributes
Asked Answered
K

3

10

I'm just playing around with the custom element functionality in Aurelia and tried to create a 'progress bar' element.

progress-bar.js

import {customElement, bindable} from 'aurelia-framework';
@customElement('progress-bar')
export class ProgressBar
{
//do stuff//
}

progress-bar.html

<template>
  <link rel="stylesheet" type="text/css" href="src/components/progress-bar.css">
  <div class='progress-bar' tabindex=0 ref="bar">bloo</div>
</template>

test.html (relevant portion)

  <require from="./components/progress-bar"></require>
  <progress-bar ref="pb">a</progress-bar>

All of this shows up fine. But I'm struggling on how to get the main page can call some function or change some attribute on element, which should then in term do something on the progress bar itself.

I tried to create a function 'doSomething' inside the progress-bar.js but I can't access it in test.js.

Added to progress-bar.js

doSomething(percent, value) {
  $(this.bar).animate('width: ${percent}%', speed);
}

inside test.js

clicked() {
   console.log(this.pb); // this returns the progress bar element fine
   console.log(this.pb.doSomething); //this returns as undefined
   this.pb.doSomething(percent, value); // this fails outright with error: typeError - doSomething is not a function
}

Next I tried to setup custom attributes inside progress-bar element and maybe use valueChange to change the div instead.

Inside progress-bar.js

@bindable percent=null;
@bindable speed=null;

test.js

clicked() {
this.pb.percent=50; //this updated fine
this.pb.speed=1500; //this updated fine

}

No problem there, almost there. But How do I set up a handler to call when an attribute changes?

I found a tutorial which had this syntax:

@bindable({
  name:'myProperty', //name of the property on the class
  attribute:'my-property', //name of the attribute in HTML
  changeHandler:'myPropertyChanged', //name of the method to invoke on property changes
  defaultBindingMode: ONE_WAY, //default binding mode used with the .bind command
  defaultValue: undefined //default value of the property, if not bound or set in HTML
})

But I can't seem to use that code in my progress-bar.js. The page fails to render properly after I add that in. Gulp doesn't seem to have returned any error messages but the browser console returns this error:

ERROR [app-router] Router navigation failed, and no previous location could be restored.

Which is the message I normally get when I have some syntax error somewhere on my pages.

There are many things I'm unsure of here:

Is this the right use for custom elements? Can we create custom elements with functions inside them? Can we create custom elements with custom attributes which can then trigger events when its values change?

Apologies for not posting entire codes, as I have so many variations of it while trying out different things.

Kellikellia answered 5/7, 2015 at 17:33 Comment(2)
I figured it out. this.pb refers to the progress-bar element. Inside it is a progressBar object of class ProgressBar. So to access functions inside the custom element class its this.pb.progressBar, and same with the attributes.Kellikellia
If you've answered your problem, can you post your actual solution and then mark it as the answer?Throughout
C
17

With Aurelia, you can use this convention in your component : yourpropertynameChanged()

import {customElement, bindable, inject} from 'aurelia-framework';
import $ from 'jquery';

@customElement('progress-bar')
@inject(Element) 
export class ProgressBar
{
    @bindable percent;
    @bindable speed;

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

    percentChanged(){
        doSomething(this.percent, this.speed);
    }

    speedChanged(){
        doSomething(this.percent, this.speed);
    }

    doSomething(percent, value) {
        $(this.element).animate('width: ${percent}%', value);
    }
}

You don't need to access to the doSomething() from outsite.
But you just need to change the properties:

<progress-bar percent="${pb.percent}" speed="${pb.speed}">a</progress-bar>
Comstockery answered 6/7, 2015 at 9:43 Comment(1)
Thanks, this is sort of what I ended up with.Kellikellia
S
4

I've taken a simpler lazier approach and am using nprogress, you can use nprogress.set(0.4) but I'm using the default "something is happening" behaviour.

import nprogress from 'nprogress';
import {bindable, noView} from 'aurelia-framework';

@noView
export class LoadingIndicator {
  @bindable loading = false;

  loadingChanged(newValue){
    newValue ?
      nprogress.start() :
      nprogress.done();
  }
}
Soldo answered 8/7, 2015 at 10:9 Comment(0)
C
1

First bind some object to your custom element, for example "config":

<custom-element config.bind="elementConfig"></custom-element>

then in your page js file:

someFunction(){ this.elementConfig.elementFunction(); }

and in your custom element add a function like this:

@bindable({ name: 'config', attribute: 'config', defaultBindingMode: bindingMode.twoWay });
export class JbGrid {
    attached() {
        this.config.elementFunction = e=> this.calculateSizes();
    }
    calculateSizes() {
    //your function you want to call
    }
}

Now you have access to custom element "this" in your function.

Collate answered 15/4, 2017 at 13:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.