Unable to access VM properties from #inlineView - aurelia

I've created a simple custom element in Aurelia that uses an #inlineView() (because the view is tiny) but when I try to access one of my VM's properties from my inline view I just get "property is not defined";
import {inlineView} from 'aurelia-framework';
#inlineView(`<template><h1>${title}</h1></template>`)
export class MyCustomElement {
constructor () {
this.title = 'Hello, World!';
}
}
This happens with #bindable as well;
export class MyCustomElement {
#bindable title = 'Hello, World!';
constructor () {
}
}

When the <template><h1>${title}</h1></template> is being interpreted, the interpreter tries to interpolate the title variable which does not exist yet. Try this:
#inlineView(`<template><h1 innerHTML.bind="title"></h1></template>`)
Or even easier:
#inlineView('<template><h1>${title}</h1></template>') // without accents

The problem is you are using a template literal in your inlineView decorator which is causing Javascript to evaluate ${title} before it gets passed to the inlineView decorator function. At that point, title does not exist. You need to pass a regular string in this instance using regular quotes (' or ") around the template string like so:
#inlineView("<template><h1>${title}</h1></template>")

Related

Vuex: add to prototype so I can do something like object.save()?

All my Vuex modules use base UPSERT, UPDATE, DELETE functions so I would love to not type this.$store.dispatch('UPSERT', object) in my components and instead type object.save(). I assume this is easy, but not sure if there are any issues with doing this or how to do this.
export interface ITaskMessage {
id?: string
message: string | null
save(): any
}
export class TaskMessage implements ITaskMessage {
id?: string
message: string | null = ''
save() {
window._actions['UPSERT']
}
}
This code is from types.ts inside a module. I assume I need to import something in this file and then use that inside the class declaration. I'm just not sure what it should be.
It was simpler than I was making it out to be. Basically, import the store into the file:
import store from '#/store'
Then, fill in the save method:
public save() {
store.dispatch('UPSERT', this)
}

Vue.js: using a data object's method in inline event handler

I have a Vue(2.5+) component where I'm setting a data property to a new Foo object. Using foo.bar() in the click handler calls the method correctly, but throws Uncaught TypeError: cannot set property 'someVariable' of null when trying to modify properties inside the Foo class. Setting it up so that Foo is an object literal instead of a class also does not resolve the error.
I suspect something weird is happening with this, between the component and the class?
Vue component
import Foo from './foo.js'
export default {
template: `<div #click="foo.bar"></div>`,
data() {
return {
foo: new Foo()
}
},
created() {
console.log(foo); // foo is not null here
}
}
Foo class
export default class Foo
{
constructor()
{
this.someVariable = 0;
}
bar(e)
{
// modify this.someVariable
}
}
but if I change the vue component to reference the external method through it's own "methods" property, it works.
Vue component (working)
import Foo from './foo.js'
export default {
template: `<div #click="bar"></div>`,
data() {
return {
foo: new Foo()
}
},
methods: {
bar(e) {
this.foo.bar(e);
}
}
}
As said in the comments, foo.bar without any context attached to it :
In JS functions are objects, just like any object they have their own this "pointer".
In the evaluation of their body, this is bound to a specific object referred to as context which is either the default context (automatically set) or user defined (manually set).
Inheritance in JS is achieved through a prototype chain and methods should be defined on/attached to the class's prototype. Because of this, when you call foo.bar() :
You are in a method call context, therefore foo will be bound to the method
bar is searched on the object first then in the prototype chain
But methods behave just like any other property : when you do foo.bar you get a reference to the actual method which is an unbound function (default behavior for methods, since it is bound when called on an object).
Therefore, what you really need to do in this situation is foo.bar.bind(foo).
I would also suggest taking a quick look into this ES6 proposal for a bind operator and its implementation as a Babel plugin which allows nice things like passing ::foo.bar instead of foo.bar.bind(foo)

Dojo2: How to get the child widget instance to call functions on it

The setup is really simple, assume this piece of code:
export default class App extends WidgetBase {
protected render() {
return v('div', [
w(MyCustomWidget, {}),
v('button', {
id: 'abc',
classes: ['btn', 'btn-primary'],
onclick: this.clickMe
}, [
'Hello World!'
])
]);
}
}
The class MyCustomWidget defines now a function which I want to call from the current App-widget. If I do let cw = w(MyCustomWidget, {}) I get an object with the key instance which contains exactly what I want. But if I use cw.instace TypeScript tells me, that Property instance does not exist on type 'WNode<MyCustomWidget>'.
So how to do it properly?
I reached out to the guys from Dojo2 and they responded to me very quickly with:
If you want a child widget to call a function from the parent you need pass it to the child as a property. In dojo the widget instance are never exposed.
This was also my workaround but I was not sure if this was the correct way to do it. It certainly works. Now we know.

Setter is invoked before constructor

I am trying to create instances of class HelloWorld, however it does not work. I found that problem is that setter methods called instead of constructor which should initialize variable name, while variable welcome is optional.
I specified getters and setters for both variables. Browser's console is throwing an error about maximum call stack size. If I comment my getters&setters it stops throwing errors.
Could anyone explain me that strange behaviour?
Also there is another problem with mapping. I'm trying to "return" an array if li elements like in React by using .map(). It gives me the result with commas. How can I get rid of them while printing?
This is a link to my code https://codepen.io/CrUsH20/pen/yzMjzL?editors=1010
Updated #1
I fixed the problem with getters&setters by giving a _ sign for private values.
Now I have a problem with
function print() {
if (invitations) {
document.getElementById('result').innerHTML = invitations.map((e)=> {
return `<li>${e.welcome + e.name}</li>`;
});
}
}
Compiler complains that Type 'string[]' is not assignable to type 'string'. in document.getElementById('result').innerHTML while type was not assigned since it is a html element
Update #2
There are solutions:
1# About conflict with constructor and set&get - I changed object's values by adding to their names _. It solved the conflicts.
2# About commas - I added after map .join('') which solved my problem.
The following code (subset of yours) is a compile error:
class HelloWorld {
constructor(public name: string) {
}
set name(e: string) {
this.name = e;
}
get name(): string {
return this.name;
}
}
Garbage in => Garbage out
Fix
Dont use getter / setters and properties with the same name.

Typescript error when using interface from module as field within class

I am working on providing a type definition file for fabric.js. The general structure is shown in the following sample:
declare module fabric {
export interface Canvas {
selectionBorderColor: string;
selectionColor: string;
...
}
var Canvas: {
new (): Canvas;
}
}
This pattern allows me to use fabric.Canvas in a 'interface-like' way, so that variables are associated with the fabric.Canvas interface. At the same time it allows me to call "static members" (such as the constructor of fabric.Canvas).
But this leads to a problem when using a field of interface 'fabric.Canvas' within a class. The following sample shows such an case:
This problem only occurs when placing the interface within a module, otherwise everything works fine.
Any solutions for this problem?
There is some type confusion because you have an interface and a field with the same name - I know this is common in the lib.d.ts file, but I don't think it is a good practice when writing new TypeScript code. It seems to be something of a necessity for defining existing code.
If you rename var Canvas to var MyCanvas (or anything else) your code works.
I tend to prefix my interfaces with an I, for example ICanvas - but this isn't a TypeScript convention (yet).
declare module fabric {
export class Canvas {
selectionBorderColor: string;
selectionColor: string;
}
}
class MyClass {
canvas: fabric.Canvas;
}