Vue3 and Element plus dynamic column not show data - vuejs3

I try to loop through Element-plus table column as <el-table-column v-for="(d ,i) in data.values" :key="i" :prop="d.value" :label="d.label" /> but no result showed in browser I trying google for hours and trying several examples and solutions but nothing works for me on this issue.
full example here
<template>
<el-table :data="data" class="full-table">
<el-table-column fixed prop="name" label="Employee" width="250"/>
<el-table-column prop="phone" label="Phone"/>
<el-table-column v-for="(d ,i) in data.values" :key="i" :prop="d.value" :label="d.label" />
</el-table>
</template>
<script setup lang="ts">
import {ElTable, ElTableColumn} from 'element-plus'
const data = [
{
name: 'personal1',
phone: 6767000,
values: [
{
label: 'email',
value: 'personal1#mail.com',
}
]
},
{
name: 'personal2',
phone: 9090000,
values: [
{
label: 'email',
value: 'personal2#mail.com',
}
]
},
]
</script>
The result is show like this no extra column for v-for
What do i do wrong?. please advice

You don't need value in the template as explained here.
Try with v-for="(d ,i) in data" and :prop="d".
Also, feel free to double check what you have in your Vue devtools to be sure.
I don't have an Element UI example but this is how the Vue part works when using the Composition API.
<template>
<div v-for="(d ,i) in data" :key="d.name" :prop="d" :label="d.label">
{{ d.name }}
</div>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
const data = reactive([
{
name: 'personal1',
phone: 6767000,
values: [
{
label: 'email',
value: 'personal1#mail.com',
}
]
},
{
name: 'personal2',
phone: 9090000,
values: [
{
label: 'email',
value: 'personal2#mail.com',
}
]
},
])
</script>
Overall, I recommend that you give a read to that part of the doc to have a fully usable Vue example with some working reactivity.
Element UI's prop will follow up accordingly.

Related

make input search box full screen overlay on click on mobile device

I am using buefy autocomplete input fields in my nuxtjs project, this is location search box, what i want is just for mobile device, when i click the input field, it should overlay on full screen with suggestion like i attached screenshot below and after select suggestion, it should close and return to normal.
here is my simple auto complete input field code.
<template>
<b-autocomplete
v-model="pickupairport"
:data="airports"
name="pickupairport"
class="ttc-search-input"
icon="map-marker-outline"
placeholder="Pickup Airport"
field="name"
:loading="isFetching"
#typing="getairports"
#select="(option) => (aptselected = option)"
>
<template slot-scope="props">
<div class="media">
<div class="media-content">
{{ props.option.name }}
<br />
<small> {{ props.option.cityName }}, {{ props.option.countryName }} </small>
</div>
</div>
</template>
</b-autocomplete>
</template>
<script>
import { debounce } from 'lodash'
export default {
data() {
return {
pickupairport: '',
airports: [],
aptselected: null,
isaptFetching: false,
}
},
methods: {
getairports: debounce(function (pickupairport) {
const aptsearchq = this.pickupairport
if (!pickupairport.length) {
this.airports = []
return
}
this.isaptFetching = true
fetch(`https://api.myurl.com/api/transfers/aplist?querystring=${aptsearchq}`)
.then((response) => {
return response.json()
})
.then((data) => {
this.airports = []
data.response.forEach((item) => this.airports.push(item))
})
.catch((error) => {
this.airports = []
throw error
})
.finally(() => {
this.isaptFetching = false
})
}, 500),
},
}
</script>
What I want to achieve is like this GIF - https://i.imgur.com/zOYPwBI.gif
What I have now is like this GIF - https://imgur.com/9ZBZzxa
i tried to find something related, but couldn't find, if any suggestion on how to achieve that, it would be helpful for me.

Apostrophe CMS align custom layout widget

I'm sure there's a really simple solution to this but I can't seem to find it, and I haven't found the question asked here already.
I'm trying to align a layout widget (area) so that when another widget is added it appears to the right of the first widget and not below.
I was hoping i could sort this with flexbox and the artistContainer class but it doesn't seem to be possible.
Dev tools and desired outcome
home.html
<section class="bodysect--dark" id="artists">
<h2 class="body__heading">Artists</h2>
<div class="artistContainer">
{{
apos.area(data.page, 'artist', {
widgets: {
artist: {}
}
})
}}
</div>
</section>
Widget.html
<div class="artist">
<div class="artistImage">
{{ apos.singleton(data.widget, 'areaImage', 'apostrophe-images', {
widgets: {
'apostrophe-images': {}
}
}) }}
</div>
<div class="artistName">
{{ apos.singleton(data.widget, 'singletonName', 'apostrophe-rich-text', {
widgets: {
'apostrophe-rich-text': {}
}
}) }}
</div>
<div class="artistBio">
{{ apos.singleton(data.widget, 'singletonBio', 'apostrophe-rich-text', {
widgets: {
'apostrophe-rich-text': {}
}
}) }}
</div>
</div>
widget index.js
module.exports = {
extend: 'apostrophe-widgets',
label: 'Artist',
contextualOnly: true,
addFields: [
{
name: 'artistImage',
type: 'singleton',
label: 'Image Area',
required: true
},
{
name: 'artistName',
type: 'singleton',
label: 'Name Area',
required: true
},
{
name: 'artistBio',
type: 'singleton',
label: 'Bio Area',
required: true
},
]
};
Thanks in advance!
There is nothing preventing you from lining up horizontally, however, to maintain the proper flex contexts, you'll need to apply styles to apostrophe-generated markup instead of just your project level classes. Here is some sample code I just demo'd
.horizontal-area {
.apos-area-widgets, // proper context for logged-in user
.apos-area { // proper context for logged-out user
display: flex;
}
.apos-area-widget-wrapper {
flex-grow: 1;
flex-basis: 0;
}
}
http://g.recordit.co/IlOPYKRUo0.gif
You might want to provide additional UI changes to adjust the horizontal Add Content line within the horizontal area scope.

Responsive and dynamic background images in Vue.js

I'm trying to build a vue.js front-end and the design is calling for 100% width tiles with a dynamic background image that will be passed along the rest of the content to the page. I already have the payload passing to the component that renders each tile, but I need to render the background image for each of the tiles. I also need to mention that the images are actually 3 images for each tile that need to render for each of our 3 breakpoints. So far I was able to pass one image by using :style="'background-image: url(' + backgroundImage + ')'" but this only serves one image per tile. My question is, what would be the best way to pass all 3 images per tile and render them correctly?
I have heard online that I should just use srcset and pass all 3 to an <img> tag, and make that image the background by using CSS, but that just seems unorthodox.
Is there a more elegant way to deal with responsive background images in reusable components in vue.js?
Home Page
<template>
<div class="Home">
<HomePageTile v-for="tile in tiles" :key="tile.title" :tile-title="tile.title" :tile-desc="tile.description" :tile-type="tile.position" :background-image="tile.backgroundImage"/>
</div>
</template>
<script>
import HomePageTile from '#/components/HomePageTile'
import tileImage1 from '#/assets/optimized/image1.jpg'
import tileImage2 from '#/assets/optimized/image2.jpg'
import tileImage3 from '#/assets/optimized/image3.jpg'
import tileImage4 from '#/assets/optimized/image4.jpg'
export default {
name: 'Home',
components: {
HomePageTile: HomePageTile
},
data () {
return {
tiles: [
{
title: 'Title 1',
description: 'Content 1',
position: 'right',
backgroundImage: tileImage1
}, {
title: 'Title 2',
description: 'Content 2',
position: 'right',
backgroundImage: tileImage2
}, {
title: 'Title 3',
description: 'Content 3',
position: 'right',
backgroundImage: tileImage3
}, {
title: 'Title 4',
description: 'Content 4',
position: 'right',
backgroundImage: tileImage4
}
]
}
}
}
</script>
Tile Component
<template>
<div :class="tilePosition(tileType)" :style="'background-image: url(' + backgroundImage + ')'">
<template v-if="tileType">
<div class="home-page-tile--container home-page-tile--container__with-desc">
<h2 class="home-page-tile--container--title">{{ tileTitle }}</h2>
<p class="home-page-tile--container--description">{{ tileDesc }}</p>
</div>
<div class="home-page-tile--call-to-action" v-if="callToAction">
<p class="home-page-tile--call-to-action--text">{{ callToAction.text }}</p>
<Button class="home-page-tile--call-to-action--button" :button-route="callToAction.buttonPath" :button-text="callToAction.buttonText" :button-style="callToAction.buttonStyle" />
</div>
</template>
<template v-else>
<div class="home-page-tile--container">
<h2 class="home-page-tile--container--title">{{ tileTitle }}</h2>
<Button :button-route="buttonPath" :button-text="buttonText" button-style="pill"/>
</div>
</template>
</div>
</template>
<script>
import Button from './Button'
export default {
name: 'HomePageTile',
props: {
tileType: String,
tileTitle: String,
tileDesc: String,
backgroundImage: String,
buttonText: String,
buttonPath: String,
callToAction: Object
},
components: {
Button: Button
},
data () {
return {
tilePosition: function (el) {
if (el) {
return 'home-page-tile home-page-tile__' + el
} else {
return 'home-page-tile'
}
}
}
}
}
</script>

In Polymer 1 how can I wrap a distributed template with another element?

I have a custom element (let's say my-view) which receives as effective children a template with some annotations for the data binding.
How can I wrap the distributed template with another custom element, let's say paper-item?
This is my working code.
<my-view>
<template>[[ item.name ]]</template>
</my-view>
Inside my-view I have
<template id="Repeater" is="dom-repeat">
</template>
and
_templatize() {
const repeater = this.$.Repeater
const template = this.queryEffectiveChildren('template')
repeater.templatize(template)
}
What I want to achieve is wrapping the template effective children with another custom element (let's say paper-item).
Something like
_templatize() {
const repeater = this.$.Repeater
const template = this.queryEffectiveChildren('template')
const item = this.create('paper-item')
item.appendChild(template.content)
repeater.templatize(item)
}
which of course doesn't work.
Perhaps I understood you wrong, but you don't create a page structure like the example you gave. Use the HTML elements first, and spice it up with javascript, if needed.
<dom-module id="my-view">
<template>
<template is="dom-repeat" items="[[anArrayWithStrings]]" as="someValue">
<paper-item>[[someValue]]</paper-item>
</template>
<template is="dom-repeat" items="[[anArrayWithObjects]]" as="employee">
<paper-item two-line>
<div>[[employee.name]]</div>
<div>[[employee.title]]</div>
</paper-item>
</template>
</template>
<script>
Polymer({
is: 'my-view',
properties: {
anArrayWithStrings: {
type: Array,
value: function() { return ['firstOne', 'secondOne', 'thirdOne']; }
},
anArrayWithObjects: {
type: Array,
value: function() { return [
{'name': 'Sarah', 'title': 'accountant'},
{'name': 'Ingrid', 'title': 'engineer'} ]; }
},
},
ready: function() {
//enter code here
},
</script>
</dom-module>
I just wrote this on freehand, without testing, so there could be some faulty code in there, but this is an example of how it could look like.

Pushing data to object in different component using POST

TL;DR I want to show submitted posts instantly instead of having to refresh my page
Using the Wordpress REST API I am able to create a new post without any issue. The post is being displayed as soon as the page refreshes, so what I want to do is update the posts object in my Hello.vue file as soon as I create that post so I don't need to refresh to show my newest posts.
I'm not really sure where to start - I've removed all of the experiments I've done so far (importing Post in Create, defining props, pushing to an array, reading about object reactivity on the official Vue documentation, nothing helped).
My App.js consists of the <router> object which shows Hello.vue and a component called Create which displays the Create.vue component. This is how my app currently looks like:
My App.vue file:
<template>
<div id="app">
<section class="posts">
<router-view></router-view>
<create></create>
</section>
</div>
</template>
<script>
import Create from '#/components/Create.vue'
export default {
name: 'app',
components: {
Create
}
}
</script>
<style lang="scss">
#import '../src/assets/styles/style.scss'
</style>
My Hello.vue which displays all the posts:
<template>
<div>
<section class="posts__Feed">
<ul class="posts__List">
<post v-for="item in posts" :item="item" :key="item.id"></post>
</ul>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
import Post from '#/components/Post.vue'
export default {
name: 'hello',
props: ['responseData'],
components: {
Post
},
data () {
return {
posts: []
}
},
beforeCreate () {
this.$http.get(postsUrl).then((response) => {
this.posts = response.data
})
}
}
</script>
And finally, the Create.vue file which creates the post:
<template>
<div>
<section class="posts__Create">
<form class="posts__CreateForm" v-on:submit="createPosts">
<div class="posts__CreateFormWrapper" v-bind:class="{ 'is-Loading': loading }">
<p>
<input v-model="formInfo.title" type="text" name="title" id="title" placeholder="Name" :disabled="formSent">
</p>
<p>
<textarea v-model="formInfo.content" name="content" id="content" cols="20" rows="10" maxlength="140" placeholder="Message" :disabled="formSent"></textarea>
</p>
<p>
<button :disabled="formSent">Send</button>
</p>
</div>
</form>
</section>
</div>
</template>
<script>
var postsUrl = '/wp-json/wp/v2/posts/'
export default {
name: 'create',
data () {
return {
formInfo: [],
responseData: [],
loading: false,
formSent: false
}
},
methods: {
createPosts (e) {
e.preventDefault()
var info = this.formInfo
// Check if fields are empty
if (this.formInfo.title && this.formInfo.content) {
this.loading = true
// POST
this.$http.post(postsUrl, info).then((response) => {
this.formSent = true
this.loading = false
// get body data
this.responseData = response.data
})
}
} // EOF createPosts
}
}
</script>
Any help would be much appreciated!
I ended up using an event bus as suggested by wotex. First, I've createad a file called bus.js with the below code:
import Vue from 'vue'
export const EventBus = new Vue()
Next, import bus.js to both .vue layouts using:
import { EventBus } from '#/bus.js'
Now emit the event as soon as a new post is created (this is sitting in my axios POST request inside the Create.vue file):
EventBus.$emit('newPost', this.responseData)
And finally, check if the event has happened on the other end (my Hello.vue file):
EventBus.$on('newPost', function (postData) {
Thanks for pointing me in the right direction!

Resources