angular2 Can't have multiple template bindings on one element - javascript

I have this angular2 template:
<template *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</template>
I get these errors:
zone.js:461 Unhandled Promise rejection: Template parse errors:
Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with * (" </div>
<div *ngSwitchCase="false" class="container p-t-10">
<alert *ngIf="alerts.length > 0" [ERROR ->]*ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert"): b#5:37
what's the problem I put *ngIf and *ngFor in defferent html elements. It should work. no?
and:
Can't bind to 'type' since it isn't a known property of 'alert'. (""container p-t-10">
<alert *ngIf="alerts.length > 0" *ngFor="let alert of alerts;let i = index" [ERROR ->][type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
"): b#5:80
I added the
*ngIf="alerts.length > 0 to avoid cases of alert = []. How can i fix it otherwise?

The * in *ngFor makes Angular to add a <template> tag. On a <template> tag this doesn't make sense and therefore here structural directives have a different syntax.
<template ngFor [ngForOf]="alerts" let-alert let-i="index">
Because different syntax for almost the same on different places caused quite some confusion, the Angular team recently introduced
<ng-container>
that behaves similar to the <template> tag (is not added to the DOM) but allows the more common syntax
<ng-container *ngIf="alerts.length > 0">
<alert *ngFor="let alert of alerts;let i = index" [type]="alert.type" dismissible="true" (close)="closeAlert(i)">
{{ alert?.msg }}
</alert>
</ng-container>

You should use <ng-container> for this case. As a example:
<ng-container *ngIf="totalItems > 0">
<tr *ngFor="let item of outputs| paginate: { id:'ab', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>
<ng-container *ngIf="totalItems > 10">
<tr *ngFor="let item of outputs| paginate: { id:'aabbbbbbbbb', itemsPerPage: pageSize, currentPage: currentPage, totalItems: totalItems }; let $index = index">
<td>{{item.x}}</td>
<td>{{item.y | date: 'MMMM d, y, h:mm:ss a' }}</td>
<td>{{item.z}}</td>
<td>{{item.r}}</td>
</tr>
</ng-container>

Related

How to use ternary operator inside component with v-for directive?

The working code looks as following:
<template lang="pug">
b-carousel.d-none.d-sm-block(
id='categoryRoulette'
controls
no-animation
:interval='0'
)
b-carousel-slide(
v-for="category in chunkedArr"
:key="category.permalink"
)
template(v-slot:img)
b-card-group(deck)
b-card(
v-for="(item, index) in category" :key="index"
:img-src='item.image'
img-alt='Image'
img-top
tag='article'
style="min-width: 250px;"
)
b-card-text.d-flex.justify-content-center.align-items-center
h5
a(href="#") {{ item.title }}
</template>
But, I need to check if item.image exists and if not to display blank image as following:
<template lang="pug">
b-carousel.d-none.d-sm-block(
id='categoryRoulette'
controls
no-animation
:interval='0'
)
b-carousel-slide(
v-for="category in chunkedArr"
:key="category.permalink"
)
template(v-slot:img)
b-card-group(deck)
b-card(
v-for="(item, index) in category" :key="index"
:img-src='item.image ? item.image : '../assets/images/blank.png''
img-alt='Image'
img-top
tag='article'
style="min-width: 250px;"
)
b-card-text.d-flex.justify-content-center.align-items-center
h5
a(href="#") {{ item.title }}
</template>
But, this line is not working:
:img-src='item.image ? item.image : '../assets/images/blank.png''
How to check item.image? Maybe, there is another way?
You can't use ' nested in another ', so change it to "
:img-src='item.image ? item.image : "../assets/images/blank.png"'
or
:img-src="item.image ? item.image : '../assets/images/blank.png'"

Clicking on row in v-data-table with template rows

When I added template rows (so that they have special formatting based on condition):
<v-data-table
:headers="headers"
:items="desserts"
:items-per-page="5"
class="elevation-1"
#click:row="clickedHandle"
>
<template v-slot:item="props">
<tr v-if="props.item.name.includes('Fro')">
<td>{{ props.item.name }}</td>
<td v-for="itemx in myheaders">{{ toThousands(props.item[itemx]) }}</td>
</tr>
<tr v-else>
<td v-for="itemx in props.item">{{ itemx }}</td>
</tr>
</template>
</v-data-table>
The function that is supposed to be called on row click clickedHandle does not fire up at all. Why is that so?
Here is the example where you can check this behaviour:
https://codesandbox.io/s/vuetify-playground-forked-lro4w?file=/src/layout.vue
The table does not seem to react on row click at all.
clickedHandle(value) {
console.log(value);
},
clickedHandle should log some value on row click.
Customize each cell individually as they do in the v-data-table row customization docs, not the whole row. You can use a v-for to dynamically target the cell slots you want (in conjunction with your myheaders array):
<template v-for="header in myheaders" v-slot:[`item.${header}`]="props">
<template v-if="props.item.name.includes('Fro')">
{{ toThousands(props.item[header]) }}
</template>
<template v-else>
{{ props.item[header] }}
</template>
</template>
You could avoid this slot and filter complexity by preparing your data ahead of time in a computed.
Here is an updated CodeSandbox
try with this code:
<v-data-table
:headers="headers"
:items="desserts"
hide-actions
class="elevation-1"
>
<template slot="items" slot-scope="myprops">
<tr v-if="myprops.item.name.includes('Fro')">
...
</tr>
<tr v-else>
<td v-for="itemx in props.item">{{ itemx }}</td>
</tr>
</template>
</v-data-table>

Vuejs & Vuetify : Is there a way to loop around template with datatable from vuetify (with v-slot dynamic)?

I have several datatable with server-side pagination, search fields and filterable fields
However, I would like to be able to generate a component and use the props to avoid modifying the same thing three times
Is there a way to loop around template with datatable from vuetify (with v-slot dynamic) ?
for example :
<template v-slot:header.id="{ header }">
<div class="pointer border-right pa-2">
<span class="title" #click.prevent="sortBy('id')">
ID
<v-icon class="ml-2">{{icon.id}}</v-icon>
</span>
<v-text-field v-model="searcher.ticket_id.value" type="text"
label="Rechercher..."></v-text-field>
</div>
</template>
<template v-slot:header.name="{ header }">
<div class="pointer border-right pa-2">
<span class="title" #click.prevent="sortBy('name')">
Nom du ticket
<v-icon class="ml-2">{{icon.name}}</v-icon>
</span>
<v-text-field v-model="searcher.ticket_name.value" type="text"
label="Rechercher..."></v-text-field>
</div>
</template>
Become (not functional) :
<template v-for="(item, i) in headers" v-slot:item.text="{ header }">
<div class="pointer border-right pa-2">
<span class="title" #click.prevent="sortBy(item.name)">
{{item.name}}
<v-icon class="ml-2">{{icon[item.name]}}</v-icon>
</span>
<v-text-field v-model="item.searcher" type="text"
label="Rechercher..."></v-text-field>
</div>
</template>
If i add the key , i have '<template>' cannot be keyed. Place the key on real elements instead
and if i remove this i have Elements in iteration expect to have 'v-bind:key' directives
However I came across several sources that demonstrate the opposite
https://v2.vuejs.org/v2/guide/list.html#v-for-on-a-lt-template-gt
Fix: require-v-for-key shouldn't be raised on slots
vue-language-server : Elements in iteration expect to have 'v-bind:key' directives
Thank you
Edit 20/12 :
https://github.com/vuejs/eslint-plugin-vue/issues/1006
How can I make the v-slot attribute dynamically with the vuetify data table ?
Here is my code :
<template v-for="(head, i) in headers" v-slot:header[header.value]="{header}">
<div :key="i" class="pointer border-right pa-2">
<span class="title" #click.prevent="sortBy('id')">
{{head}} <br> {{header}}
<v-icon class="ml-2">{{icon.id}}</v-icon>
</span>
<v-text-field v-model="searcher.ticket_id.value" type="text"
label="Rechercher..."></v-text-field>
</div>
</template>
It cannot be mounted on the table column
I need to use v-slot:header.id="{header}" for the mounted on the id column but I have to make id dynamic according to my loop
how to do ?
Thank you
I find it
I added head: 'header.id' in my list so i can use <template v-for="(head, i) in headers" v-slot:[headers[i].head]="{header}">
I had to do
<template v-for="(col, i) in filters" v-slot:[`header.${i}`]="{ header }">
in my case
filters: { 'name': [], 'calories': [] },

Defining default emit events in a Vue JS component template

I havetwo nested Vue JS components. The child component emits a few events to the parent function which I define inside the parent component declaration. However these same few events are being called every time I am going to be using the component, so I want to be able to omit having to declare them within the props of the parent component. However I am unsure as to where to move the event declarations in the parent component props.
<admin-data-table
:dataTable="dataTable"
:modelName="modelName"
:collection="collection"
:tblShowFields="tblShowFields"
:selectedList.sync="selected"
#change-sort="changeSort"
#edit-row="edit"
#remove-row="remove"
></admin-data-table>
The #change-sort, #edit-row, and #remove-row events will always be defined this way every time I use admin-data-table component, so I want to be able to omit having to declare them.
I tried moving them into the template tag of the child component [admin-data-table], which did not work.
admin-data.table component:
<template
#change-sort="changeSort"
#edit-row="edit"
#remove-row="remove">
<v-flex xs12>
<v-progress-linear :indeterminate="true" :height="3" color="#c79121" :active="dataTable.loadingVal" class="mb-0 mt-5"></v-progress-linear>
<v-data-table :ref="modelName + 'Table'" :value="selectedList" #input="$emit('update:selectedList', $event)" :headers="dataTable.headers" :items="collection" :pagination.sync="dataTable.pagination" select-all item-key="id" class="elevation-1" >
<template v-slot:headers="props">
<tr>
<th><v-checkbox :input-value="props.all" color="#c79121" :indeterminate="props.indeterminate" primary hide-details #click.stop="toggleAllSelected"></v-checkbox></th>
<th v-for="header in props.headers" :key="header.text"
:class="['column sortable', dataTable.pagination.descending ? 'desc' : 'asc', header.value === dataTable.pagination.sortBy ? 'active' : '']"
#click="$emit('change-sort', header.value)">
<v-icon small>arrow_upward</v-icon>
{{ header.text }}
</th>
</tr>
</template>
<template v-slot:items="props">
<tr :active="props.selected">
<td class="text-center align-middle" #click="props.selected = !props.selected">
<v-checkbox :input-value="props.selected" primary hide-details color="#c79121"></v-checkbox>
</td>
<td v-for="(field, key) in props.item" v-if="tblShowFields.includes(key)">{{ field }}</td>
<td class="text-right align-middle">
<v-btn
v-for="(btn, i) in dataTable.rowButtons" :key="i"
:title="btn.title"
:color="btn.color" fab small
#click="btn.click">
<v-icon>{{ btn.icon }}</v-icon></v-btn>
<v-btn title="Edit" color="primary" fab small #click="$emit('edit-row', props.item.id)"><v-icon>edit</v-icon></v-btn>
<v-btn title="Delete" color="error" fab small class="text-white" #click="$emit('remove-row', props.item.id)"><v-icon>delete_outline</v-icon></v-btn>
</td>
</tr>
</template>
<template slot="no-data">
<p class="text-xs-center">No Data</p>
</template>
</v-data-table>
</v-flex>
</template>
<script>
export default {
name: "admin-data-table",
props: [
'dataTable',
'collection',
'modelName',
'collection',
'selectedList',
'tblShowFields'
]
}
</script>
Where can I map these into the admin-data-table component itself as defaults?
I hope I am understanding this correctly. You can set property defaults in vue if you specify the properties as objects instead of an Array.
props:{
'edit-row':{
type:Function,
default: (itemID) => { //function logic}
}
}
VueJS Prop Validation
If you look under the object example they show actually how an object needs to return a function as a default prop. You can then overwrite these props with another outside function if you include one.

django-templatetag-handlebars - declare repeated template code once

I am using django 1.7 & python 2.7. It is all still quite new to me so I am still learning.
I am also using django-templatetag-handlebars in my templates.
I have a dynamic template that uses the same template code several times in the same template.
How do I declare the repeated code once and then reference it where I need it? Handlebars.js uses partials, but I am not so sure how I can use partials in the django-templatetag-handlebars.
Here is my template code:
{% load templatetag_handlebars %}
{% tplhandlebars "address_details_live_preview_template_ltr" %}
....
{{# if address_style_01 }}
{{! Address Style: 1 }}
{{# if address_line_1 }}
{{ address_line_1 }}<span class="spacer"></span>
{{/if}}
{{# if address_street_details }}
{{ address_street_details }}<span class="spacer"></span>
{{/if}}
{{# if address_locality }}
{{ address_locality }}<span class="spacer"></span>
{{/if}}
{{# if address_country_name }}
{{ address_country_name }}
{{/if}}
{{else}}
....

Categories

Resources