Polymer 1.0 Data Binding to rowspan attribute - polymer

I'm creating dynamic data driven tables with Polymer 1.0 using data binding:
<tbody>
<template is="dom-repeat" items="{{instInfo}}" as="instItem">
<tr>
<td rowspan="{{instItem.rowSpan}}">{{instItem.name}}</td>
</tr>
<template is="dom-repeat" items="{{instItem.rows}}" as="row">
<tr>
<template is="dom-repeat" items="{{row}}" as="rowItem">
<td>{{rowItem}}</td>
</template>
</tr>
</template>
</template>
</tbody>
All of the data bindings above work fine except for the td rowpsan (line 4). When I use a real number, all is well.
Is data binding to an html attribute possible?

Use attribute$="{{value}}" rather than attribute="{{value}}".
Per the polymer documentation:
To bind to an attribute, use $= rather than =. This results in a call to:
element.setAttribute(attr, value);
As opposed to:
element.property = value;

Related

Vue Warn the client side rendered virtual DOM tree is not matching server-rendered content

I'm trying to loop a tr within a table with Vue.js and Nuxt. But when I load the page I get the following error
vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered
virtual DOM tree is not matching server-rendered content. This is
likely caused by incorrect HTML markup, for example nesting
block-level elements inside , or missing . Bailing hydration
and performing full client-side render.
When I remove the table from the following block of code from my HTML the error disappears. How can this be happening? I checked all closing tags and they seem to be matching. What is happening here?
In Template
<template>
<ContentBlock id="statistics" class="content-light">
<div class="content-grid-light">
<div class="content-grid-item-1">
<div>
<table class="table">
<tr v-for="(statistic, index) in statistics" :key="index" :value="statistic">
<th class="table-cell">{{statistic.key}}</th>
<td class="table-cell statistic-value">{{statistic.value}}</td>
</tr>
</table>
</div>
</div>
</div>
</ContentBlock>
</template>
In Script
data(){
return{
statistics: [
{key:"TestKey1", value:"TestValue1"},
{key:"TestKey2", value:"TestValue2"},
{key:"TestKey3", value:"TestValue3"},
{key:"TestKey4", value:"TestValue4"},
],
}
},
Here is my rendered html
Html
The answer depends on the version of your nuxt project. If the version is v<2.9.0, wrap your table with no-ssr tag. Otherwise use client-only tag like below:
version < 2.9.0:
<no-ssr>
<table></table>
</no-ssr>
version > 2.9.0
<client-only>
<table></table>
</client-only>
Tip: pay attention that no-ssr is going to be removed in nuxt 3.
Marvin Rudolph helped me out on the Nuxt discord. I needed to add a tbody around my tr and the error was gone
make sure to wrap your component markup with a template/container no other element should be outside the template/container.
for example:
<template>
<div id="app">
<table class="table">
<tr v-for="(statistic, index) in statistics" :key="index" :value="statistic">
<th class="table-cell">{{statistic.key}}</th>
<td class="table-cell statistic-value">{{statistic.value}}</td>
</tr>
</table>
</div>
</template>
no element should be outside the #app tag
The object you are trying to loop over is not correct as it should be for a v-for the rendered html shows [object Object] as value of each tag, try this instead
<template>
<ContentBlock id="statistics" class="content-light">
<div class="content-grid-light">
<div class="content-grid-item-1">
<div>
<table class="table">
<tr v-for="(statistic, index) in statistics" :key="statistic.key" :value="statistic.value">
<th class="table-cell">{{statistic.key}}</th>
<td class="table-cell statistic-value">{{statistic.value}}</td>
</tr>
</table>
</div>
</div>
</div>
</ContentBlock>
</template>
if this does not solves the problem you can use the tag as suggested here

Create an Angular component to display a set of html table cells to embed in other tables

I have a lot of html tables that share the same 15 columns along with custom columns that are specific for each table. I would like to create these common 15 columns as a component that takes in a set of data and shows up as the 15 td's without a wrapper. I can't figure out how to create an Angular component that doesn't show the wrapper tag in the DOM and allows me to pass in input. Below is kind of what I'd like to do:
<tr *ngFor="let item of items">
<td>Column 1</td>
<my-common-columns [data]="item"></my-common-columns>
<td>Another column</td>
</tr>
Unfortunately with the above code, <my-common-columns> tag shows up in the rendered DOM, which messes up the table. I can only have td's under the tr tag.
I also tried <ng-container *ngComponentOutlet="myCommonColumns"> since ng-container's don't show up in the DOM, but I can't figure out how to pass data into it.
import { Component, TemplateRef, ViewChild } from '#angular/core';
#Component({
selector: 'my-common-columns',
template: `<ng-template let-item>
<td>inner item1:{{item}}</td>
<td>inner item2:{{item}}</td>
</ng-template>`
})
export class CommonComponent {
#ViewChild(TemplateRef) template: TemplateRef<any>;
}
#Component({
selector: 'my-app',
template: `
<table>
<tr *ngFor="let item of data">
<td>first</td>
<ng-template [ngTemplateOutlet]="common.template"
[ngTemplateOutletContext]="{$implicit: item}">
</ng-template>
<td>last</td>
</tr>
</table>
<my-common-columns #common></my-common-columns>
`
})
export class AppComponent {
data = [1, 2, 3, 4, 5];
}
live example
result:
ngComponentOutlet will show tag in HTML too.
Either, you should use abstraction to display tables for complex problems.
Depending on your data structure you could probably do something like:
<td *ngFor="let col of item">{{ col }}</td>
You have to use your component as a attribute.
So put it to <td my-common-column></td> and in your component change selector: [my-common-column]. These [ ] brackets allows you to use component as attribute.
Why don't you use the code below?
<tr *ngFor="let item of items">
<td>Column 1</td>
<td> {{ item }}</td>
<td>Another column</td>
</tr>

Vue v-bind - access array object from another array loop

I'm working on a project where I created a table component which is used on multiple pages with different configuration. Every table has it's configuration in a separate file where I store keys, titles and size classes for each column.
Data for each table body come from REST calls and they are loaded dynamically, paginated and then displayed.
<template slot="thead">
<tr>
<th v-for="item in headers" :key="item.id" :class="item.classes">{{item.title}}</th>
</tr>
</template>
<template slot="tbody">
<tr v-for="skill in paginatedSkills"
:key="skill.id"
v-on:click="selectRow(skill)"
v-bind:class="{selectedRow: selectedSkill === skill}"
>
<td class="cell-l">{{skill.name}}</td>
<td class="cell-m">{{skill.owner}}</td>
<td class="cell-s">{{skill.complexity}}</td>
<td class="cell-full">{{skill.description}}</td>
</tr>
</template>
What I want to do is to avoid writing size class for every single cell in the tbody loop. I was hoping to get index of looped object and use it to retrieve the class from config object which is used to populate cells in thead.
<tr v-for="(skill, index) in paginatedSkills" ...>
<td class="{headers[index].classes}">{{skill.name}}</td>
Using index on headers will return the correct item but as a string so obviously classes are not accessible. Any idea how to tweak it?
This options are no go, failing on compile
<td :class="{JSON.parse(headers[index]).classes}">{{skill.name}}</td>
<td :class="{JSON.parse(headers)[index].classes}">{{skill.name}}</td>
<td :class="{{JSON.parse(headers[index]).classes}}">{{skill.name}}</td>
To set class from a variable/property you have two options:
<td v-bind:class="headers[index].classes">{{skill.name}}</td>
<td :class="headers[index].classes">{{skill.name}}</td>
No need for curly braces here since v-bind already expects JS expression.
Update:
What you can also do, is to associate keys of skill object (name, owner, complexity, description) with their header, so each item of headers array will also have for example key property used to access value from skill object:
headers: [
{ id: 1, classes: 'cell-l', title: 'title', key: 'name' },
{ id: 2, classes: 'cell-s', title: 'title', key: 'owner' },
...
]
Thus, your code can be simplified the following way:
<tr v-for="skill in paginatedSkills" ...>
<td v-for="header in headers" v-bind:class="header.classes">{{skill[header.key]}}</td>
</tr>

Angular 2+ : Condition based on previous index date value ngIf NgFor

Trying to format a table using Angular where:
If the day of the month changes, then you insert a new row which just contains the date (but also displays the data for that index value immediately below). If the day of the week is the same as before continue inserting the rows.
1) Clearly my code for accessing previous value in index is wrong but I can't seem to find anything clearly which helps.
2) I realise that my current code would compare the full datetime value and not just the day of the month (or week) but I am unsure how to do this in this scenario.
3) when the day changes and I try and insert the date line, I cannot get an additional new row formatted correctly which includes the data for that index value. I have tried playing around with various and combinations.
Please could someone help correct this code or point me in the right direction
Thanks
<table class="table-striped">
<thead>
<tr>
<td>day</td>
<td>time</td>
<td>region</td>
<td>event</td>
<td>period</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let eco of eco_r ; let i = index">
<template [ngIf]="eco.date != eco[i-1].date">
<td colspan="5">{{eco.datetime| date:'longDate' }}</td>
<tr>
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>
<template [ngIf]="eco.date == eco[i-1].date">
<td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td>{{eco.region}}</td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</template>
</tr>
</tbody>
</table>
------------UPDATE ---------------
Following #Iancovici comments I have revised the following
i) corrected to reference eco_r[i-1].date
ii) Changed sql source to provide eco.day_of_month and eco.week_of_year to make it easier to reference and check conditions
iii) updated code to only check previous value when i > 0
I am still unable to get it to display a new line with the date AND also include the data for that value of i on a separate row where it formats correctly. Utilising as in my revised code puts all 5 values into the first column of the next row and messes put the table format. How should I resolve this please?
Thanks
<template [ngIf]="i >0 && eco.day_of_month != eco_r[i-1].day_of_month">
<tr><td colspan="5">{{eco.datetime| date:'longDate' }}</td>
</tr>
<tr> <td>{{eco.datetime | date:'EE'}}</td>
<td>{{eco.datetime | date:'shortTime'}}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</template>
Should probbly be *ngIf not [ngIf] in general. But I see in your case it’s ok because you’re using an ng template which means instead of directive *ngIf it’s not a bonded property [ngIf]
Also you're accesing the same instance, should access index of array instead so..
change from
*ngIf="eco.date == eco[i-1].date">
to
*ngIf="eco.date == eco_r[i-1].date">
Update: Two more notes
Make sure you create a table, with tag
Don't be afraid to use paranthesis if conditonal expressions become more complex, so you can distinguish the two conditions.
Try this without the filters, then integrate the filters in.
<table>
<div *ngFor="let eco of eco_r; let i = index">
<div *ngIf="(i > 0) && (eco.day_of_month != eco_r[i-1].day_of_month)">
<tr>
<td colspan="5">{{eco.datetime }}</td>
</tr>
<tr>
<td>{{eco.datetime }}</td>
<td>{{eco.datetime }}</td>
<td> {{eco.region}} </td>
<td>{{eco.event}}</td>
<td>{{eco.period}}</td>
</tr>
</div>
</div>
</table>

PolymerJS : Calling function on load in table element

I want to call the searchByID() when the table cell values are iteratively loaded:
Here is what I have already and I would like to search the DB and return the value for the ID. (This is done by my searchByID()) All i care about how it is rendered
Code snippet:
<template id="course-table-rows-template" repeat="{{item in response.entries}}">
<tr>
<td>
{{item.id}}
<form is="ajax-form" action="/add_to_wishlist?course_id={{item.id}}" method="get" id="add-course">
<button id="wishlist_add_button" on-click="{{handleWishlistClick}}">+ Wishlist</button>
</form>
</td>
<td>{{item.title}}</td>
<td>{{item.description}}</td>
<!--{{item.primary_category_id}}-->
<td>
<form is=""ajax-form" action="> How do I call the searchByID on load? I dont want to create a button and do an on click</form>
</td>
<td>{{item.primary_subcategory_id}}</td>
</tr>
</template>
What I want to do: Use the item.primary_subcategory_id and query the DB, and put that value in the .
LMK if you need more code for explanation.
You can listen to domReady event. It will be fired if all dom elements ready to query. More info about Polymer event you can check it at https://www.polymer-project.org/0.5/docs/polymer/polymer.html#lifecyclemethods