Can't bind to '*ngIf' since it isn't a known property of 'td' in angular2 - angular2-template

in my angular 2 application In ts file i have below click even,
ViewPages(Char: string): void {
this.selectedPage = Char;
}
In html, i tried to bind select page in ngif
<td *ngIf="name[0] == {{selectedPage}}">{{name}}</td>
but it is throwing the ""Can't bind to '*ngIf' since it isn't a known property of 'td'.
it will be grt help if someone help me regarding this

You should use ng-container for this. It isn't added to resulting html.
<ng-container *ngIf="name[0] == {{selectedPage}}">
<td>{{ name }}</td>
</ng-container>
And make sure, that CommonModule is imported.
import { CommonModule } from '#angular/common';
#NgModule({
imports: [
CommonModule
]
})

Apart from importing Common module in app.module.ts, we must declare the custom components created. Look for the html file in the console error and declare the corresponding component in app.module.ts

Related

Property not defined on the instance but references during render

I am using VueJS 2.5.16, in a sfc way with TypeScript and vue-class-component
My BookingTable.Vue:
<template>
<div>
<button class="refresh-button" v-on:click="refresh()"><img src="../assets/Data-Synchronize.png"></button>
<table>
<tr v-bind:key="booking.id" v-for="booking in bookings">
[...]
</tr>
</table>
</div>
</template>
<script lang="ts">
class Booking {
Id : number = 0;
StartTime : string = '';
EndTime : string = '';
EnergyConsumed : number = 0;
User : number = 0;
Parking : number = 0;
Plug : number = 0;
Charging : boolean = false;
Cancellation : string = '';
}
export default class BookingTable extends Vue {
bookings : any;
[Other properties and methods]
</script>
And this is the Warning that VueJS is throwing :
[Vue warn]: Property or method "bookings" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
I already searched through both stack overflow and github issues section but I could not undertand where my mistake was. So if someone can explain it to me, i'll be very grateful :)
Thank you
data is what is bound in the template scope. It doesn't look like you have data defined anywhere. You can even see this in the Microsoft Vue TypeScript example.
Use this:
export default class BookingTable extends Vue {
data(): {
return {
bookings: [];
}
}
}
Alternatively it looks like you can use decorators to declare properties as well per this example in the same repository from above: HelloDecorator.vue

importing components in ngx-bootstrap throws 'not a known element' error

I imported the datepicker and it shows up fine.
But when I try to import a typeahead or buttons or anything, I get the <whatever> is not a known element error.
What I'm doing is import the module in the app.module like that:
import {DatepickerModule} from 'ngx-bootstrap/datepicker';
import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
import { ButtonsModule } from 'ngx-bootstrap/buttons';
// also tried:
// import { DatepickerModule, TypeaheadModule... } from 'ngx-bootstrap';
// ..but again no luck
...
imports: [
DatepickerModule.forRoot(), //only this works
TypeaheadModule.forRoot(),
ButtonsModule.forRoot(),
...]
Then on my history.module in a same way with the only difference that .forRoot() is now omitted.
Then on a child component of the parent history component I have:
<span *ngIf="showFilters" class="value bootstrap-iso" >
<div style="display:inline-block;">
<datepicker
[(ngModel)]="dt"
[datepickerMode]="'month'"
[showWeeks]="false"
[dateDisabled]="dateDisabled"
[maxDate]="today">
</datepicker>
</div>
</span>
which works, but for example these don't work:
<typeahead [typeahead]="'documents'"></typeahead>
<btnCheckbox></btnCheckbox>
Doesn't matter if I include ngModel or other attributes, I always get the not a known element error. So I assume it has to do with my imports, my naming, or somethng, but honestly I can't see what's missing.
EDIT: Using Angular 4, "#angular/cli": "1.1.1", "ngx-bootstrap": "^1.7.1", "bootstrap": "^4.0.0-alpha.6", "typescript": "~2.3.3"
Well, I actually have to add the input shown in the template section in the documentation.
So this works:
<input [(ngModel)]="selected"
[typeahead]="documents"
class="form-control">
Because the documentation mentions Selector and Exported as I thought we should use these values. I thought the templates are just showing how the components work under the hood.
As my collegue said , please add
import {FormsModule, ReactiveFormsModule} from '#angular/forms';

Custom Attribute on Aurelia not working

I am a beginner by Aurelia. I want to program a Custom Attribute as you see here:
square.js:
/*jshint esversion: 6 */
import {bindable, inject} from 'aurelia-framework';
#inject(Element)
export class SquareCustomAttribute {
#bindable sideLength;
#bindable color;
constructor(element){
this.element = element;
}
sideLengthChanged(newValue, oldValue){
this.element.style.width = this.element.style.height = `${newValue}px`;
}
colorChanged(newValue, oldValue){
this.element.style.backgroundColor = newValue;
}
}
and you can see html in the following:
<template>
<require from="./square"></require>
<div square="color.bind: squareColor; side-length.bind: squareSize"></div>
</template>
I get an error:
ERROR [app-router] Error: (SystemJS) Unable to dynamically transpile ES module as SystemJS.transpiler set to false.
Could you please help me?
An easy way to do what you are trying to do (not purely an attribute) is this:
try this:
square.html
<template bindable="sideLength, color">
<div css.bind="height: ${sideLength}; width: ${sideLength}; background-color: ${color}"/>
</template>
now you just use it like this:
[any].html
<require from="[path]/[to]/square.html"></require>
.
.
.
<square side-length="50" color="red"></square>
.
.
.
There is almost an exact example of this under data binding in the docs:
Aurelia Docs: Cheat Sheet - Databinding
Creating an answer so this can be closed.
User had an error with his script file causing the transpiler to fail. Changing the file extension from .js to .ts solved the issue as the TypeScript file could be handled by SystemJS.

How dynamic add events to a tag in my custom grid component

<template>
<tbody>
<template v-for="(row,index) in datalist">
<tr #click="rowevent != null?rowevent(row,this.$el):''" :class="index % 2 === 0?bodytrclass[0]:bodytrclass[1]">
<td v-if="col.show" v-for="col in collist" #click="eventbus(row,$event)" #mouseover="eventbus(row,$event)">
<template v-if="col.type">
<component v-for="com in col.type" :is="com" :rowdata="row" :colname="col.colname"
:tdcbfun="col.cbfun"></component>
</template>
<template v-else>{{ row[col.colname] }}</template>
</td>
</tr>
</template>
</tbody>
</template>
```
now a question
`<tr #click="rowevent != null?rowevent(row,this.$el):''" :class="index % 2 === 0?bodytrclass[0]:bodytrclass[1]">`
how can i add events by data (props) ? dynamic v-on?
i don't want to write #click #mouseover #.......
i want like this ....
```
props: {
trevent: [{event:'click',eventfun:function (rowdata) {
if(rowdata.age<10){ //#:click=eventfun(rowdata)
alert('children')
}
}},{event:'mouseover',eventfun:function (rowdata) {
if(rowdata.age<10){//#mouseover=eventfun(rowdata)
tip('children')
}
}}]
}
```
another example button component
```
<template>
<div>
<button #click="eventbus" #mouseover="eventbus">{{options.btnname}}</button>
</div>
</template>
methods: {
eventbus: function (rowdata, event) {
var eventname = event.type
var eventpos = event.currentTarget.localName
this.$root.$emit(eventpos + eventname, rowdata)
}
}
vm.$on('trclick',function(){
.......do something
})
```
if sometime emit not $on dont do it ...this kind of settlement so .....
and i also can use component :is but javaer must write component so much
oh v-if
Sorry for my english..
终于可以写中文了
我们公司正在开发一个公共组件,刚开始做现在正在做表格的组件。
这个组件是通用的,想用在公司的不同的系统上,也是开源的。
麻烦大家帮看看 现在如何可以 根据传入的props 数据 ,动态添加事件到某个标签上?
我找不到办法动态添加v-on
想做的功能多一些 还不想总让研发人员写动态的component
我尽量将vue封装成 jquery那种调用形式,大家都比较容易会。
其次是我现在在mainjs 里把vue写好的组件暴露出来window.$grid = grid.vue 然后在引入webpack打包好的js
然后直接使用 请问还有其他更好的关于把vue做成组件在外部调用的例子吗?
还有如果我这种方式引用的话 是否还能使用vue-router ? 最好给个例子
最近半个月狂看Vue 在此感谢下尤大弄出这么好的东西!
借这里给大家拜个早年,祝各位在新的一年里身体健康,生活幸福!
英语不好麻烦各位了
One possible approach could be using the special propr ref and adding the event listener in mounted lifecycle. since it is added manually, you may want to remove it too, so I would add it in beforeDestroy life cycle.
Set the ref to the tag
<tr ref="my-tag" :class="index % 2 === 0?bodytrclass[0]:bodytrclass[1]">
Add and Remove the event in the livecycles
mounted() {
this.$refs['my-tag'].addEventListener(this.myEvent,() => {
// Some logic..
});
},
beforeDestroy() {
this.$refs['my-tag'].addEventListener(this.myEvent,() => {
// Some logic..
});
}
It may not be the nicer approach but would do the trick.
It is maybe not the best concept to modify the event listeners of a components DOM afters it was compiled. If found this quote from Evan You (creator of vuejs) here:
I think you are approaching this with wrong assumptions. Templates for a component is static, once it's defined you can't change it. You need to express the parts that may be changed inside the template.
It is possible to recompile a component template as Elfayer shows here, but it does not improve elegancy for this problem since one has to provide a template for every configuration of the properties. For one event attribute it's no problem, you would need two templates. But for three events you would already need 8 templates and so on...
Option 1: Handle logic within normal event handlers
Use normal event handlers which perform conditional execution of dynamic event listeners.
In your template you could replace
<template>
...
<tr #click="rowevent != null?rowevent(row,this.$el):''" :class="index % ...
...
</template>
with:
<template>
...
<tr #click="tr_handler(row,this.$el)" :class="index % ...
...
</template>
and then use the tr_handler() method to check whether there is an event listener assigned to a certain property or not:
methods: {
//...
tr_handler: function(row,e) {
if (this.rowevent) {
return this.rowevent(row, e)
}
}
//...
}
This approach provides a clean structure and keeps the string template feature of vuejs.
Option 2: Use a render() function
One can render the whole template dynamically by using a render function. Also it is possible to apply event listeners to the nodes as described within the latter link:
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
`~!mouseover`: this.doThisOnceInCapturingMode
}
Both approaches do not avoid declaring the event within the template.
Here is some statement about this which explains how things are done in vue-world.
Since you don’t have to manually attach event listeners in JS, your
ViewModel code can be pure logic and DOM-free. This makes it easier to
test.

Getting element height

I was curious if I can get element properties form component template.
So I have made simple div with class and I've made this class:
export class viewApp{
elementView: any;
viewHeight: number;
myDOM: Object;
constructor() {
this.myDOM = new BrowserDomAdapter();
}
clickMe(){
this.elementView = this.myDOM.query('div.view-main-screen');
this.viewHeight = this.myDOM.getStyle(this.elementView, 'height');
}
}
getStyle(), query() are from BrowserDomAdapter.
My problem is when I try to get height it is null, but when I set some height by setStyle() and then I get it by getStyle() it returns proper value.
After checking DOM and styles in browser I discovered that is because of two CSS elements. One is: .view-main-screen[_ngcontent-aer-1]{} and second one is element{}.
.view-main-screen has some stylings, but element is empty. When I add styles by setStyle() it appears in element{}. Why is that? How can I get element properties by using Angular2?
The correct way is to use #ViewChild() decorator:
https://angular.io/docs/ts/latest/api/core/index/ViewChild-decorator.html
Template:
<div class="view-main-screen" #mainScreen></div>
Component:
import { ElementRef, ViewChild } from '#angular/core';
export class viewApp{
#ViewChild('mainScreen') elementView: ElementRef;
viewHeight: number;
constructor() {
}
clickMe(){
this.viewHeight = this.elementView.nativeElement.offsetHeight;
}
}
That should do it but obviously you need to add your Component decorator.
Edit:
For Angular 8 or later you need to provide the 2nd parameter in ViewChild
#ViewChild('mainScreen', {read: ElementRef, static:false}) elementView: ElementRef;
update2
constructor(private elementRef:ElementRef) {}
someMethod() {
console.log(this.elementRef.nativeElement.offsetHeight);
}
Accessing nativeElement directly is discouraged but current Angular doesn't provide other ways as far as I know.
update
https://github.com/angular/angular/pull/8452#issuecomment-220460761
mhevery commented 12 days ago
We have decided to remove Ruler service, and so it is not part of the public API.
original
As far as I know the Ruler class should provide that functionality
https://github.com/angular/angular/blob/master/modules/angular2/src/platform/browser/ruler.ts if this isn't enought you probably need to access elementRef.nativeElement and use direct DOM access and functions provided by the elements.
new Ruler(DOM).measure(this.elRef).then((rect: any) => {
});
Rules service is safe in WebWorker.
See also the comments on https://github.com/angular/angular/issues/6515#issuecomment-173353649
<div #getElementHeight>
Height
</div>
Height of element is {{ getElementHeight.offsetHeight }}
<div *ngFor="let item of items" (click)="itemClick($event.currentTarget)"></div>
itemClick(dom){
var height=dom.clientHeight;
// ...
}