vuejs: Component for <tr>, how to implement? - vue.js

After reading docs & forums for hours... still have no answer.
Have the following JS/HTML:
Vue.component("my-component", {
props: ["id"],
render: function(h) {
return h("tr", this.$slots.default);
}
});
var vapp = new Vue();
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<table>
<tr is="my-component" :name="yo">
<td>
<span v-text="name"></span>
</td>
</tr>
</table>
Use tr + "is" attribute to specify component within the table otherwise browser will hoist it out as invalid content. Done
Use render + h("tr"...) because vuejs doesn't render tr element, but instead table > td and again browser hoist it out.Done
Now I have table > tr > td rendered well but how can I add children bound to the props/data, so I will see "yo" on the screen.
Thanks a lot!

If the elements in the slot need access to data inside the component, then you need to use a scoped slot.
Since you are using a render function, the scoped slot is available as a function through this.$scopedSlots.default() and you pass it an object with the data you want to be made available to the scoped slot.
You also need to define the scoped slot in the template. Here is an example.
Vue.component("my-component", {
props: ["id", "name"],
render: function(h) {
return h("tr", this.$scopedSlots.default({name: this.name}));
}
});
var vapp = new Vue({ el:"#app"});
<script src="https://unpkg.com/vue#2.4.2/dist/vue.js"></script>
<div id="app">
<table>
<tr is="my-component" :name="'yo'">
<template scope="{name}">
<td>
<span v-text="name"></span>
</td>
</template>
</tr>
</table>
</div>

If you are using .vue files you can have the table row component defined like this:
<template>
<tr>{{ name }}</tr>
</template>
<script>
export default {
name: 'table-row',
props: ['name'],
};
</script>
Then use it like this:
<table>
<tr is="TableRow" name="Some name here"></tr>
</table>

<table>
<thead>
<!-- ...some th -->
</thead>
<tbody>
<tr>
<td>..</rd>
</tr>
<template> <row-component my-param="blabla"></row-component> <!-- component return full row <tr>...</tr> -->
<some-other-recomponent my-par="blabla"></some-other-recomponent> <!-- component return full row <tr>...</tr> -->
</template>
</tbody>
</table>

If your're interested in returning multiple rows from your component, you can do like this.
In your main component.
<table width="90%">
<thead>
<tr>
<th width="1%">#</th>
<th>header description</th>
</tr>
</thead>
<template>
<your-child-component
:prop="prop-data"
v-for="(lancamento, index) in lancamentos"
:key="lancamento.id">
</your-child-component
</template>
</table>
And inside your child component
<template>
<tbody> <!-- dont forget this tag -->
<tr>
<td rowspan="2" v-html="prop.id"></td>
<td><td>
</tr>
<tr>
<td colspan="2" class="text-center"></td>
</tr>
</tbody>
</template>

Related

search bar filter using Vue js

I am trying to filter a table that get data from api and I tried this solution but it doesnt work.
I couldnt find where the problem is and if I pass the search input event listener
and here is my table component :
<template>
<table class="mt-12 border-2 border-gray-600">
<thead>
<tr>
<th v-for="header in data.headers" :key="header" class="text-left border-l-2 border-gray-600 border-b-2 border-gray-600 bg-red-400 ">{{ header }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(rows, index) in data.rows" :key="index">
<td v-for="row in rows" :key="row" class="border-l-2 border-gray-600" >{{ row }}</td>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
data: Object,
default: {}
}
}
</script>
<style src="../assets/tailwind.css"/>
My question:
If anyone can help me to define my problem and solve this ?
Thanks for help.
You can use your data as computed where you pass it as a prop.
<BaseTable :data='data' />
Here instead of using like this create a computed which can be filteredData.
<BaseTable :data='filteredData' />
and in your props you can simply filter it or just send the data as it is.
computed: {
filteredData() {
if(this.search) {
// filter your data as you want and return
}
else // return your main data
}
}
Here is a working simple example:
https://codesandbox.io/s/filterlist-example-vdwhg?file=/src/App.vue
And change your include to includes.
what error you are getting ? I think you are using this.search inside filteredRows function which is not a vue instance property. it should be this.data.search. The search is used with V-model as well so you should declare it outside data (JSON object).

inject render method into template

Must the render method of a Vue component be used exclusively or can it be combined with a template? Most of my component can be rendered using a template but just need a small part of it to be rendered using code. If this is possible how can I combine the render method output with the template?
Example in component:
<template>
<table>
<tr>
// use render method here
</tr>
<tr v-for="row in rows">
// use render method here
</tr>
</table>
</template>
Need render method in spots above to loop through the array $scopedSlots.column and render each <th> and <td> based on multiple <templates v-slot:column={row}> provided by parent.
As far as I know you can either use the render function or a template - but not both. They can not be combined.
What you could do to make your example work is to use the v-html-directive, which updates the innerHTML of an element https://012.vuejs.org/api/directives.html#v-html.
new Vue({
el: '#el',
data: {
rows: ['row1', 'row2', 'row3']
},
methods: {
renderRow(row) {
return `<td>${row}</td>`;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="el">
<table>
<tr v-for="row in rows" v-html="renderRow(row)">
</tr>
</table>
</div>
I'm having this same challenge as well. Which is how I came to your question.
As others have said, it seems you can either use a template or render function but not both.
My suggestion would be to have a component handle only the render function, while the parent component can use the template method
So, Per your example
<template>
<table>
<tr>
<component-using-only-render-method />
</tr>
<tr v-for="row in rows">
<component-using-only-render-method />
</tr>
</table>
</template>
I think its the best of both worlds with minimal compromise

Fixed Column on HTML Table with Vue JS

I'm having a problem with my table when I scroll to the right
this is my code
TableComponent.vue
<div id="main-container">
<table class="maint-table">
<thead id="table-header">
<tr>
<th class="dates"> </th>
<th v-for="data in dateHeader">{{data}}</th>
</tr>
<tr>
<th class="title"> </th>
<th v-for="data in dayOfWeek">{{data}}</th>
</tr>
</thead>
<tbody id="table-body" #scroll="fixedScroll">
<table_block :table_data="dataHeader"></table_block>
<table_block :table_data="allData"></table_block>
</tbody>
</table>
</div>
...
...
...
<script>
components: {
table_block
},
methods: {
fixedScroll() {
fixedScroll(event) {
var thead = document.getElementById("table-header");
var tbodyScroll = document.getElementById("table-body").scrollLeft;
thead.scrollLeft = tbodyScroll;
}
</script>
I made a props to pass the data to my TableBlock to loop through the data and display it on the table. This is my TableBlock Code.
TableBlock.vue
<template>
<div>
<tr v-for="row in table_data">
<td>
<div class="drop-down-container"><span class="drop-down-controller"">{{ row.title }}</span></div>
</td>
<td v-for="cel in row.data" class="group-header">{{ cel }}</td>
</tr>
</div>
</template>
When I scroll it to the right, the first column must freeze but it's not.
I tried to create a dummy data inside TableComponent.vue with a normal HTML Table without passing the data to another component using props, it works perfectly. But when I use these codes, it doesn't work correctly.
Scenario
Let say I have 10 columns in the table, when I scroll it to the right, the 1st column will stick which is normal but when the 10th column reach to 1st column, the 1st column will scroll away together with the 10th column.
I'm trying my best to illustrate the scenario but this is the best that I can do. If someone can help, please help me.

Child component not updating when data chaining - why does :key need to be the value that changes?

I had a table row that was like this:
<tr v-for="(pricing, idx) in pricings"">
<td>{{pricing.description}}</td>
<td>$ {{pricing.unconfirmed_price_formatted}}
</tr>
I wanted to migrate this table row to a component. However, when I change the underlying data (this.pricings), the child component doesn't update. I am calling it like this:
<pricing-row v-for="(pricing, idx) in pricings" :key="pricing.id + pricing.description" :pricing=pricing v-on:updateAfterSave="savedData" v-on:showModal="showAddEditModal"></pricing-row>
The strange thing is that the underlying array is changing - just this component is not properly updating.
It's also clear that if we use as a key the value that changes (unconfirmed_price_formatted in this case), it does update.
I'm a bit baffled by this behavior. Any ideas on what is wrong?
edit 1
here is the component:
<template>
<tr>
<td>{{localPricing.description}}</td>
<td v-if="localPricing.price">$ {{localPricing.price_formatted}} {{localPricing.units_display}}</td>
<td v-else> </td>
<td v-if="localPricing.unconfirmed_price">$ {{localPricing.unconfirmed_price_formatted}} {{localPricing.unconfirmed_units_display}}</td>
<td v-else> </td>
<td v-if="localPricing.state != 'deleted'">
<!-- button class="btn btn-outline-secondary" #click="willShowModalWithBattery(pricing)">edit</button -->
<button class="btn btn-outline-secondary" #click="showModal(pricing)">edit</button>
</td>
<td v-else> </td>
</tr>
</template>
<script>
export default {
props: ['pricing'],
data: function(){
return {
localPricing: this.pricing
}
},
methods:{
showModal: function(pricing){
this.$emit('showModal', pricing);
}
}
}
</script>

Dynamic insertion of aurelia custom elements

test.html
<gid>
<grid-col prop1=""></grid-col>
<grid-col-checkbox prop1=""></grid-col-checkbox>
<grid-col-radio prop1=""></grid-col-radio>
<grid-col-custom prop1=""></grid-col-custom>
</grid>
test.js
export class Test {}
==============
grid.html
<table>
<tbody>
<td>test</td>
=======
<template classs="foo-class" repeat="">
</template>
======
</tbody>
</table>
grid.js
export class Grid {}
I want to insert the below things in table body. so that they will repeat for entire data
<grid-col prop1=""></grid-col>
<grid-col-checkbox prop1=""></grid-col-checkbox>
<grid-col-radio prop1=""></grid-col-radio>
<grid-col-custom prop1=""></grid-col-custom>
Can any one help how we can do this?
You can create a template for your table row:
my-table-row-template.html
<template>
<td>
<grid-col prop1=""></grid-col>
</td>
<td>
<grid-col-checkbox prop1=""></grid-col-checkbox>
</td>
<td>
<grid-col-radio prop1=""></grid-col-radio>
</td>
<td>
<grid-col-custom prop1=""></grid-col-custom>
</td>
</template>
NOTE: you can omit the <td></td> elements if they are already in your grid-col-x components
then to use just
<require from="my-table-row-template.html"></require>
<tr repeat.for="item of items">
<my-table-row-template item.bind="item"></my-table-row-template>
</tr>
REFERENCE: http://aurelia.io/docs.html#/aurelia/framework/1.0.0-beta.1.1.3/doc/article/cheat-sheet/4