Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aurelia: accessing Custom Element's custom functions or custom attributes

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.

like image 422
Bob Smith Avatar asked Jul 05 '15 17:07

Bob Smith


3 Answers

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();
  }
}
like image 44
Matt McCabe Avatar answered Nov 12 '22 19:11

Matt McCabe


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>
like image 90
Nicolas Pennec Avatar answered Nov 12 '22 20:11

Nicolas Pennec


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.

like image 1
javad bat Avatar answered Nov 12 '22 19:11

javad bat