Passing input properties over angular component with css class selector - angular5

I have a component with class selector. popup is component with css class selector '.popup'
<div class="popup">
My Content
</div>
I want to pass some input and output properties over it, for example, just like with normal component selector
<div class='popup' [open]="open" (afterclose)="afterclose">
</div>
But I get error - Can't bind to 'open' since it isn't a known property of 'div'.
My Component:-
#Component({
selector: '.popup',
templateUrl: './popup.component.html',
styleUrls: ['./popupx.component.scss']
})
export class PopupComponent {
#Input() open:boolean;
#Output() afterClose: EventEmitter<any> = new EventEmitter();
}
How can we achieve this?

Because you try to send data to div.
Name your component and pass data to it, for example:
<popup [open]="open"></popup>

Instead of creating a popup component, create a popup directive and use it on DIV. Then you will be able to use the inputs and outputs defined.

Related

Passing data from template to component

I have the following, which for my understanding should pass the value of html attribute to the #Prop with the same name however my console.log is always undefined. How is this accomplished?
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
#Component({})
export default class RelayComponent extends Vue {
#Prop([String]) service: string;
constructor() {
super();
console.log(this.service);
...
HTML
<template>
<div service="expecting this value passed"></div>
</template>
<script src="./relay.ts"></script>
Vue props
Vue props are intended to pass data from a parent vue component or instance to a child vue component.
So you have a vue component, you set up a #Prop and then you get the prop for the html of the parent. Should you have a my-parent and my-child components, the my-parent template could be:
<template>
<my-child count="7"></my-child>
</template>
So a child component like this:
<template>
<div class="counter">{{count}}</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Component, Prop } from 'vue-property-decorator';
#Component({})
export default class myChild extends Vue {
#Prop() count: number;
}
</script>
Would get 7 as its count prop.
Now, in your case, there is only one component, and you're trying to setup the service variable of the component from the HTML. This is sort of weird because the point of Vue is to achieve declarative rendering from the component data: is the HTML who reacts to data changes, not your component who gets data from the HTML.
(Of course, you can also setup v-model and event listeners to make your components react to user input, but that's another story).
Basically, if I understood correctly what you want to do, your issue is that you're trying to get the service prop from the HTML of the very RelayComponent component.
Instead, you should setup the service prop in the component parent:
// Code of some parent component that renders the RelayComponent
<template>
<relay-component service="this would set the service prop as a string"></relay-component>
</template>
Only, when dealing with objects, you usually don't pass down a plain string, but a javascript object, and a service variable probably is an object, so changes are you're behind something like this:
<template>
<relay-component v-bind:service="serviceVariableInTheParentComponent"></relay-component>
</template>
Where the parent component has a service variable in its data.
 Constructor and lifehooks
Be wary about explicitly calling constructor in vue class components. If you modify the component state in the constructor, you can break the component.
Probably, you should consider to ever use the created() lifecycle hook instead of constructor() in every Vue component.

Calling component method in template while v-foring the component

I'm using vuejs2. I want to create a method in my component and then call it to bind a class to it, but I can't get it to work. This is what I want to accomplish more or less, where getMachineClass() ideally would be a method in my machine component.
<machine
v-for="item in machinesList"
v-bind:key="item.id"
v-bind:machine="item"
v-bind:class="item.getMachineClass()">
</machine>
I know I can just put the method in my vue instance and then call it like this:
v-bind:class="getMachineClass(item)
I would like the method to be just in the component though. What can I do about it?
Machine component:
Vue.component('machine', {
props: ['machine'],
template: '#machine',
data: function () {
return {
translations: translations,
options: options
}
},
mounted: ...
});
You can just bind the class on the root element of your machine component
//machine component template
<script type="text/x-template" id="machine">
<div v-bind:class="getMachineClass(machine)">
//...
</div>
</script>
Since you are receiving the iterated item as a machine prop, pass it to the getMachineClass method

VueJS - Generating html string of a component in computed property

I'm looking for a suggestion regarding a cleaner approach to generate a component data as html string and to pass it raw through the props of the component.
component-a.js
import componentB from './component-b'
computed: {
tooltipHTML() {
render "<componentB :name='user1'/>
}
}
I would prefer something similar to the above idea.
Generating HTML in a computed property and passing it as props to another component to be rendered in that component will not work.
What you are looking for is Slots
Since the complete code is not provided I guess you wanted to render <componentB :name='user1'/> inside another component( a tooltip component)
You would be doing it as follows using slots:
<tooltip-comp>
<componentB :name='user1'/>
</tooltip-comp>
In your tooltip component
//tooltip component
<template>
<div class="my-tooltip">
<p>my tooltip</p>
<slot></slot>
</div>
</template>

In Aurelia, how can one one view-model affect the bound variables of another model-view

I would like the body of my application to be able to change a message shown in the header.
For example if header.html looks like this:
<template>
${message}
</template>
How could a peer view-model change that displayed 'message' variable? Or perhaps I am just going about this completely the wrong way...
The most common solution to your scenario is to use the parent viewmodel to bridge the two peers. Bind the same variable (either as a single variable or as an object) to both children using two-way binding. Then, when it changes in one, it will change in the other.
Example:
Parent view (parent.html)
<template>
<require from="./header"></require>
<require from="./my-child2"></require>
<header message.two-way="message"></header>
<my-child2 message.two-way="message"></my-child2>
</template>
Child1 viewmodel (header.js)
import {bindable} from 'aurelia-framework';
export class Header {
#bindable message;
}
Child1 view (header.html)
<template>
${message}
</template>
Child2 viewmodel (child2.js)
import {bindable} from 'aurelia-framework';
export class MyChild2 {
#bindable message;
attached() {
this.message = "Greetings from MyChild2!";
}
}
There are other ways to do this but hopefully this gets you on the right track so you can see how the binding works across views.

Aurelia custom element binding

I'm trying to build a custom element in Aurelia. At this point, this is what I have:
item.html
<template>
<span>${someProperty}</span>
</template>
item.ts
import {bindable} from 'aurelia-framework';
class Item {
#bindable someProperty: string;
}
parent.html
<template>
<require from="./item"></require>
<item repeat.for="item of items"></item>
</template>
parent.ts
class Parent {
items: Item[];
loadItems() {
// at this point, I'm sure that items is getting populated.
this.items = dataservice.loadItems();
}
}
I can't seem to find anything in the documentation that covers this scenario. What I'm getting, is that the span is empty. I'm not getting any errors in the console. Am I going about this the right way?
You need to bind to the item's someProperty. The following assumes that items[] is an array of strings.
<div repeat.for="item of items">
<item someProperty.bind="item"></item>
</div>
Sorry about the formatting, I'm on my phone.
You need to use the custom element and the bindable property. You also need to register the class as a custom element. Try this:
item.html
<template>
<span>${someProperty}</span>
</template>
item.js
import {bindable, customElement} from 'aurelia-framework';
#customElement('item')
class Item {
#bindable someProperty: string;
}
parent.html
<template>
<require from="./item"></require>
<item repeat.for="item of items" someProperty.bind="item"></item>
</template>
parent.ts
class Parent {
items: Item[] = [
'trees',
'swans',
'capes',
'a horse',
'triangles',
'witches',
'a different horse'
];
}
For more information, take a look at a few of my blogs on custom elements and custom attributes like this one: http://davismj.me/blog/semantic-custom-element/