Transition table with VueJS - html-table

I tried to continue with the example on the vuejs website. I tried to add images and a transition state when I sort data.
However it doesn't work. I have tried to add the following line to make it works but it doesn't:
<tbody name="table-row" is="transition-group">
Do you have some ideas for me?
https://codepen.io/wooza/pen/wezqXP

https://codepen.io/anon/pen/gRmxwJ
https://v2.vuejs.org/v2/guide/transitions.html#List-Transitions
Unlike <transition>, it renders an actual element: a <span> by
default. You can change the element that’s rendered with the tag
attribute.
<transition-group tag="tbody" name="table-row">
<tr v-for="entry in filteredData" :key="entry.name">
//...
</tr>
</transition-group>

Related

Vue Components Losing Image When Rerendered

I have a sidebar component located in a view-router view component that renders several child component buttons. It renders the child components using v-for loops.
<div v-for="type in this.facebookLightButtons" :key="type">
<SidebarButton :type="type"/>
</div>
<div v-for="type in this.facebookButtons" :key="type">
<SidebarButton :type="type"/>
</div>
facebookLightButtons is simply an array of strings containing the text of the button (which is also the name of the image source of the button). The result is the following:
The corresponding code in the SidebarButton components are:
<template>
<div>
<router-link :to="'/' + capitalizeFirstLetter(type)" class="sidebar-button">
<table>
<tr>
<td>
<img class="sidebar-button-icon" :src="getImage" />
</td>
<td>
<p>{{capitalizeFirstLetter(type)}}</p>
</td>
</tr>
</table>
</router-link>
</div>
</template>
and
computed: {
getImage() {
return require('#/assets/images/SidebarIcons/' + this.type + '.png');
}
}
When I change to a new view-router view and then return to the home page where this sidebar is located, the images are all missing:
I am trying to figure out how to keep the images there when returning to the home page.
Things I have tried:
Clearing and setting the image source in the SidebarButton components in the created, beforeMount, mounted, activated, deactivated, updated, and unmounted lifecycle hooks (non of which seemed to work).
Clearing the image, waiting for 2000 milliseconds using setTimeout() and then setting the image to the correct image source
Wrapping both the contents of the SidebarButton template as well as the v-for loop in the parent component with a <keep-alive> tag
Hard coding each SidebarButton component instead of using a v-for loop
It seems like something must be missing. What can I do to ensure that these images stored locally on my computer not only show when first displayed, but also appear when the user returns to the homepage after entering a separate view-router view?

Expected v-bind directive on complex <template> / v-for

I'm running into a strange issue with a complex loop I'm attempting within my component.
<template v-for="(scorecard, scorecardIndex) in scorecards">
<template v-for="(property, propertyIndex) in properties">
<!-- Primary player -->
<tr v-if="scorecardIndex === 0"
v-bind:key="propertyIndex"> // THIS LINE
</tr>
</template>
<!-- Secondary players, should only show score -->
<tr v-if="scorecardIndex > 0"
v-bind:key="scorecardIndex">
</tr>
</template>
Where I'm setting v-bind:key="propertyIndex" I'm getting the following error within VSCode
[vue/valid-v-for]
Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive.
The weird thing about this is that I don't actually get an error on my vue compiler, just within VSCode. This makes me think it has something to do directly with VSCode and not necessarily Vue itself.
You're getting this error from eslint which checks your code for possible errors and bad coding style.
When you use v-for on <template>, you need to make sure you define key on each top-level element within the <template>. This is because <template> is not an actual DOM element (within a Vue template) and so each element within it will be repeated at the same level in the DOM which is why key is required on each element at that DOM tree level.
You have a nested <template>, each using v-for, so it gets a bit more complicated. You need to make sure that the key of the first <tr> uses variables defined by both v-fors. Although in your specific case, you are using v-if to limit the element being created to only the first row, so eslint is being too pedantic here. You can silence the warning like this:
<!-- eslint-disable-next-line vue/valid-v-for -->
<tr v-if="scorecardIndex === 0"
v-bind:key="propertyIndex">
</tr>
But I think you have the order around the wrong way. It makes more sense to first check if it is the first row and then repeat a bunch of <tr>s, instead of the other way around:
<template v-if="scorecardIndex === 0">
<!-- Primary player -->
<tr v-for="(property, propertyIndex) in properties"
v-bind:key="propertyIndex">
</tr>
</template>
Lastly, you will get some duplicate key warnings because both sets of <tr>s will use keys 0, 1, 2, and so on. Maybe prefix them:
<template v-for="(scorecard, scorecardIndex) in scorecards">
<template v-if="scorecardIndex === 0">
<!-- Primary player -->
<tr v-for="(property, propertyIndex) in properties"
v-bind:key="'primary-' + propertyIndex">
</tr>
</template>
<!-- Secondary players, should only show score -->
<tr v-if="scorecardIndex > 0"
v-bind:key="'secondary-' + scorecardIndex">
</tr>
</template>

vue dom doesn't re-render

I use v-for to render table rows
<table>
<tr v-for="(item, i) in data">
<td>
<button v-if="...">....</button>
<el-tooltipplacement="right">
<button v-if="..." >...</button>
<div slot="content">
<button #click="...">...</button>
<button #click="...">...</button>
</div>
</el-tooltip>
</td>
</tr>
</table>
The tooltip is a component of element ui,
the tooltip will display after hovering the button.
The table data is gotten by ajax call,
and there are several pages,
it will get the data by ajax call while turning page,
the problem occurs after turning page.
Some tooltip will not display after hovering,
I assumed the problem is doms don't re-render,
I used $forceUpdate() after ajax call,
but it had no effect.
If you can please help me out.
element ui Tooltip component and exmaple: https://element.eleme.io/#/en-US/component/tooltip

vue.js: what's the difference between <component :is="comp-name"/> and <div :is="comp-name"/>?

When using dynamic component in vue, we could use component or html tag such as div as the tag name:
<component :is="comp-name"></component>
or:
// assume that the root tag of comp-name is div
<div :is="comp-name"></div>
So what's the difference between the 2 ways? Are the same?
The "is" attribute is not Vue specific, it comes from the Custom Element spec.
See also What is HTML "is" attribute?
But obviously Vue has to implement it on its own for its compilation, mimicking the Custom Element spec.
In the example you show, I guess it will not matter, as in both cases the tag (<component> or <div>) will be replaced by the Vue component instance. This is the typical situation of using is attribute to switch between several possible components ("dynamic components").
However it starts to matter when you try to use Custom Elements / Vue components (with runtime compilation) in some HTML elements that restrict the type of child elements they can have, as explained in the DOM Template Parsing Caveats section of Vue guide:
Some HTML elements, such as <ul>, <ol>, <table> and <select> have restrictions on what elements can appear inside them, and some elements such as <li>, <tr>, and <option> can only appear inside certain other elements.
In these cases, the is attribute may not be (only) used to switch between dynamic components, but to comply with HTML restrictions (in order to avoid the browser behaving unexpectedly to our custom components) while still replacing them later on by our custom components.
Here is a quick demonstration with a <table>:
Vue.component('my-row', {
template: '#my-row',
});
new Vue({
el: '#app',
});
td,
th {
border: 1px solid black;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<table id="table1">
<tr>
<th>Table</th>
<td>1</td>
</tr>
<!-- Below Custom component will be stripped out of the table. Exact result may differ depending on browsers -->
<my-row></my-row>
</table>
<hr />
<table id="table2">
<tr>
<th>Table</th>
<td>2</td>
</tr>
<!-- Valid TR row will be correctly replaced by Custom component -->
<tr is="my-row"></tr>
</table>
</div>
<template id="my-row">
<tr>
<th>Header</th>
<td>Cell</td>
</tr>
</template>
Result:
in Firefox, the <my-row> tag is rendered outside and above the <table>.
same in Chrome.

Access custom widget from nested element in template file (DOJO)

I am having an interesting issue with dijit widgets and widgets inside widgets. I have a custom widget that I created that houses a dijit.dialog with a form. Here is a sample
<div dojoattachpoint="WorkinProgress">
<div dojoType="dijit.Dialog" id="formDialog" title="Agent Note" >
<table>
<tr>
<td>
<label for="desc">
Description:
</label>
</td>
<td>
<input dojoType="dijit.form.Textarea" style="width:400px" type="text" name="desc" id="desc">
</td>
</tr>
<tr>
<td align="center" colspan="2">
<button dojoType="dijit.form.Button" type="submit" dojoattachevent="onclick: createNote >
SAVE
</button>
<button dojoType="dijit.form.Button" type="button" onClick="dijit.byId('formDialog').hide();">
CLOSE
</button>
</td>
</tr>
</table>
As you can see the dialog is nested inside my WorkInProgress widget. The form in the dialog itself needs to be able to call a function inside the WorkInProgress widget to post the data of the form to a webservice. I have tried using dojoattachevent but have not gotten anywhere. How do I, from the my template file, get access to the parent of the widget the dojo button resides in. Any help would be greatly appreciated. Thanks!
If you're adding the child widget dynamically, try to use dijit._Widget.placeAt function to include the DOM nodes inside. Apparently, just adding the HTML string to the parent widget only adds the root DOM of the child widget (in your case, the second div). After doing that, you should be able to get the parent info from the dojoAttachPoint, etc.
Why not give the buttons, dialog and outermost widget dojoAttachPoint attributes and then in the postCreate function of your custom widget do something like:
dojo.connect(this.createNoteButton, "onclick", this, this._createNoteHandler);
Then create a function on your custom widget called '_createNoteHandler' and do what you need to do there.
The advantages of this approach are that you can use pub/sub rather than dojo.connect for multiple handlers for 1 event, you are in greater control over the interaction, you don't litter your markup with the names of functions that may change (better separation of concerns)...