Passing Custom Attributes into Aurelia Component - aurelia

I'm having some trouble passing attributes into a custom component. I have tried declaring my component the following ways:
<require from="../components/project-documents"></require>
<project-documents projectId="testing123"></project-documents>
<project-documents projectId.bind="project.Name"></project-documents>
import {customElement, bindable} from "aurelia-framework";
import {autoinject} from "aurelia-dependency-injection";
#customElement("project-documents")
export class ProjectDocuments {
#bindable projectId:string;
attached() {
alert(this.projectId);
}
}
When the alert is called, undefined is the value I get from it. Also, is the customElement decorator required?

Instead of using camelCase for your attributes, try dash-case.
Try this:
<project-documents project-id="testing123"></project-documents>
<project-documents project-id.bind="project.Name"></project-documents>
According to aurelia conventions, dash-case'd attributes will be converted to camelCase variables in your ViewModel, so your VM is already fine.

Related

While using composition API, is there any way to re use props that are common for multiple components?

I am trying to migrate a mixin in Vue 2 to composable in vue 3. This mixin was created using class component syntax and all the form UI components (around 30 ) use this mixin. We defined all the common props in this mixin and as a result of that, all those common props were available for all the components that are using the mixin. Can we declare props within composable as well? If not, is there any other way to share reusable props from one commonplace? So that later if we need to change any one prop, we can change from one place instead of making the same change in every component that is using the prop.
import { Prop } from "vue-property-decorator";
import { Inject } from "inversify-props";
// 1: Can we use generic type in composable?
abstract class BaseForm<T> extends Vue{
// 1: This is a common property that all the form components will use
// Also some of the methods defined in this class would use this property
protected item: T = {} as T;
// 2: Common props for all the forms are defined
// Can we declare props composable as well?
// If not, is there any other way to enforce that all my components that are created using composition API
// get this prop from a commonplace?
#prop([required: true, type: Boolean])
protected edit!: boolean;
....
}

How to add custom properties to Vue modules and instances

When you inspect a Vue component that you have imported, you will get something like this:
import ClickB from 'ClickB.vue';
console.log(ClickB);
I have seen that nuxt adds a custom property there (called _nuxt), just like there is _ssrRegister. I have 2 questions:
How is it possible to add properties to the component?
Can you pass that property from the component to its instances?
It is simple. Just decorate Vue prototype like this to add instance method:
import Vue from 'vue';
// Adding an instance method
Vue.prototype.$someMethod = function (methodOptions) {
// Your own logic...
}
As a good practice, this code should be in your index.js or main.js file. Taking it one step further, you should put this code inside plugins as explained in Vue documentation for plugins.
You can always just add them to your definition and to access them you would use $options instance property.
Ref: https://v2.vuejs.org/v2/api/#vm-options

How to set a parent property from within a custom element in Aurelia?

A few days ago I asked this question 2 way databinding in Aurelia custom elements - bind custom element to parent viewmodel
Now I need to be able to reuse the allSelectableValues from my custom element (my-custom.js) in my parent element (create.js).
I need this for a custom value converter I have on create.js which contains some Ids which I need to display names for instead, by looping through the array of elements, currently fetched and residing in my custom element.
**create.html**
<td>${d.SomeID | allSelectableValuesMapping}</td>
and
**value-converters/all-selectable-values-mapping.js**
export class AllSelectableValuesMappingValueConverter {
toView(value) {
for(let item in allSelectableValues) {
if (item.SomeID == value){
return item.Name;
}
}
}
}
In the ideal world I'd have hoped something like this would have worked:
**my-custom.js**
async attached() {
this.allSelectableValues= await await this.myService.getAllValues();
this.parent.allSelectableValues = this.allSelectableValues;
}
But my custom element have no idea of the parent which is requiring it.
Does anyone have an idea how to set the parent's allSelectableValues equal to the custom element's allSelectableValues from within the custom element? Or is there another, better way of achieving it, while still maintaining the two-way databound custom element?
Something like this ?
Please take extra note of the #customElement('CustomElement') declarator above the export class CustomElement line of code.
Custom Element View Model
import {inject} from 'aurelia-framework';
import {customElement} from 'aurelia-framework';
import {bindable} from 'aurelia-framework';
#customElement('CustomElement')
export class CustomElement {
#bindable arrItems
}
Custom Element HTML
<template>
<div repeat.for="item of arrItems">$(item.someProperty}</div>
</template>
Parent View Model
export class ParentViewModel {
parentArrItems = [];
}
Parent HTML
<template>
<require from="customelement"></require>
<CustomElement arrItems.bind="parentArrItems"></CustomElement>
</template>

Using humane.js with aurelia

I'm trying to use humane.js with aurelia however I'm running in a problem.
It appears humane.js adds an element to the DOM when it's created and so far the only way I've found to do it is to force it like this....
showMessage(message) {
this.notify = humane.create();
this.notify.log(message);
}
However this creates a new instance of humane every time showMessage() is called. This breaks the queue as each one is rendered separately.
I've tried putting the create() in the activate() method of the view model but that doesn't seem to work either.
Any ideas?
This solved the problem, I've created a custom element for humane that is then included in app.html in the same way loading-indicator is in the skeleton app.
import humane from 'humane-js';
import 'humane-js/themes/original.css!';
import {inject, noView} from 'aurelia-framework';
import { EventAggregator } from 'aurelia-event-aggregator';
import { ApiStatus } from 'resources/messages';
#noView
#inject(EventAggregator)
export class StatusIndicator {
constructor(ea) {
this.ea = ea;
ea.subscribe(ApiStatus, msg => this.showMessage(msg.apistatus));
}
attached() {
this.humane = humane.create();
}
showMessage(message) {
this.humane.log(message);
}
}
The important part was the attached() this allows the setup of humane to work correctly.
Unfortunately for Aurelia, Humane will attach itself to the DOM automatically as a child of body, which Aurelia then replaces.
There is a really, really, simple fix for this:
Change your:
<body aurelia-app="main">
To this:
<body><div aurelia-app="main">
This way, Aurelia doesn't replace the div which is in body, you don't need to worry about attached() or where the import appears in your code, and humane works perfectly.
I have raised a humane github issue for this. https://github.com/wavded/humane-js/issues/69
Here is how I am using humane.js with Aurelia:
1) I load the CSS in the app index.html.
2) In each view model that requires humane, I import humane
import humane from 'humane-js/humane';
I do NOT inject human into the view model.
3) I show notifications like this:
humane.log('Error:, { addnCls: 'humane-libnotify-error' });
I hope this helps you.

Is constant polling the way Aurelia's change detection is working?

I got div with if.bind working as was suggested in this question: Using literal JavaScript values in an Aurelia view. But then I noticed that showTemplate on viewModel is being constantly checked by framework, about 10 times per second. The stack is following:
execute._prototypeProperties.visible.get (welcome.js:29)
getValue (dirty-checking.js:93)
isDirty (dirty-checking.js:127)
check (dirty-checking.js:63)
(anonymous function) (dirty-checking.js:49)
Is it supposed to be like this? Seems to be not very resource-friendly.
Best regards, Eugene.
Aurelia uses Object.observe for simple Javascript properties. If showTemplate is a function or a getter/setter, then Aurelia currently reverts to dirty checking. This can be removed by declaring the dependencies of the function. This is outlined here: https://github.com/aurelia/binding/pull/41
I have created a version of the Aurelia Skeleton project that implements this: https://github.com/ashleygrant/skeleton-navigation/tree/declare_dependencies
To implement this, you must switch to using the aurelia-main attribute. Add a main.js file:
import {LogManager} from 'aurelia-framework';
import {ConsoleAppender} from 'aurelia-logging-console';
import {ComputedObservationAdapter, ObjectObservationAdapter} from 'aurelia-framework';
LogManager.addAppender(new ConsoleAppender());
LogManager.setLevel(LogManager.levels.debug);
export function configure(aurelia) {
aurelia.use
.defaultBindingLanguage()
.defaultResources()
.router()
.eventAggregator();
aurelia.container
.registerSingleton(ObjectObservationAdapter, ComputedObservationAdapter);
aurelia.start().then(a => a.setRoot('app', document.body));
}
Then, in welcome.js, add the following import statement:
import {declarePropertyDependencies} from 'aurelia-framework';
and then outside the Welcome class, add the following method call:
declarePropertyDependencies(Welcome, 'fullName', ['firstName', 'lastName']);