Media Embed Videos not display - laravel-8

I installed ckeditor5 & mediaembed on Laravel 8
If you actually put a YouTube link, the preview will be activated.
Here is ckeditor.js
ClassicEditor.defaultConfig = {
extraPlugins: [ ImageResize ],
toolbar: {
items: [
......
]
},
image: {
toolbar: [
....
],
},
table: {
contentToolbar: [
'tableColumn',
'tableRow',
'mergeTableCells'
]
},
// This value must be kept in sync with the language defined in webpack.config.js.
language: 'ko',
mediaEmbed: {
// configuration...
previewsInData: true
}
};
After entering the YouTube link and completing the post,
In fact, when the post is opened, the code below appears and the video is not visible.
<figure class="media"><oembed url="https://www.youtube.com/watch?v=4lA57PRYxhI"></oembed></figure>
I've read the documentation several times but I can't figure out what I'm doing wrong.
I also want to add a Provider
I'm writing the code as below, and I'm wondering if this is the right approach to do it?
mediaEmbed: {
previewsInData: true,
removeProviders: ['youtube'],
providers: [
{
name: 'youtube',
url: [
/^(?:m\.)?youtube\.com\/watch\?v=([\w-]+)/,
/^(?:m\.)?youtube\.com\/v\/([\w-]+)/,
/^youtube\.com\/embed\/([\w-]+)/,
/^youtu\.be\/([\w-]+)/
],
html: match => {
const id = match[ 1 ];
return (
'<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;">' +
`<iframe src="https://www.youtube.com/embed/${ id }" ` +
'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" ' +
'frameborder="0" allow="autoplay; encrypted-media" allowfullscreen>' +
'</iframe>' +
'</div>'
);
}
},
{
name: 'afreecaTV',
url: [
/^v\.afree\.ca\/ST\/([\w-]+)/,
/^vod\.afreecatv\.com\/([\w-]+)/,
/^play\.afreecatv\.com\/([\w-]+)/,
],
html: match => {
const id = match[ 1 ];
return (
'<div style="position: relative; padding-bottom: 100%; height: 0; padding-bottom: 56.2493%;">' +
`<iframe src="https://openapi.afreecatv.com/oembed/embedinfo/${ id }" ` +
'style="position: absolute; width: 100%; height: 100%; top: 0; left: 0;" ' +
'frameborder="0" allow="autoplay; encrypted-media" allowfullscreen>' +
'</iframe>' +
'</div>'
);
}
},
]
}
$(document).ready(function () {
// $(document).load(function () {
//adjust modal body sizes
document.querySelectorAll( 'oembed' ).forEach( element => {
// console.log(element);
// console.log(element.firstChild);
// Discard the static media preview from the database (empty the <div data-oembed-url="...">).
while ( element.firstChild ) {
element.removeChild( element.firstChild );
}
// Generate the media preview using Iframely.
iframely.load( element, element.dataset.oembedUrl ) ;
} );
});
So we want to help.
When I open a post, I want to show the video
When adding ExtraProvider, is it correct to do as above?

Related

Reinitialize matterjs after page changes in nuxtjs

I have a matterjs instance in my nuxt app that drops items on the floor. Everything works when I visit the page for the first time or do a page refresh. But when I change the pages (routes) inside my app, so I come back to the page with the matterjs instance, the instance is gone. I always have to do a page refresh...
How can I reinitialize matterjs?
Fallbox
<section class="fallbox">
<div class="fallbox-content">
<nuxt-link to="/"><h1>Index</h1></nuxt-link>
</div>
<div class="fallbox-scene">
<div v-for="item in items" :key="item.className">
<span :class="item.className" class="item"></span>
</div>
</div>
</section>
export default {
data() {
return {
items: [
{
className: "-i1",
},
{
className: "-i2",
},
{
className: "-i3",
},
{
className: "-i4",
},
{
className: "-i5",
},
],
};
},
mounted() {
window.addEventListener("DOMContentLoaded", () => {
this.startFallbox();
});
},
methods: {
startFallbox() {
const Engine = Matter.Engine;
const Render = Matter.Render;
const Runner = Matter.Runner;
const Bodies = Matter.Bodies;
const Body = Matter.Body;
const Composite = Matter.Composite;
const MouseConstraint = Matter.MouseConstraint;
const engine = Engine.create();
const world = engine.world;
engine.gravity.y = 1;
const fallbox = document.querySelector(".fallbox-scene");
const render = Render.create({
element: fallbox,
engine,
options: {
width: fallbox.offsetWidth,
height: fallbox.offsetHeight,
},
});
// Render.run(render);
const runner = Runner.create();
Runner.run(runner, engine);
const itemArray = this.items;
itemArray.forEach((i) => {
const get = document.getElementsByClassName(i.className)[0];
get.style.opacity = 1;
const item = {
w: get.clientWidth,
h: get.clientHeight,
body: Bodies.rectangle(
Math.random() * window.innerWidth,
Math.random() * -1000,
get.clientWidth,
get.clientHeight,
{
restitution: 0.5,
angle: Math.random() * 360,
}
),
elem: get,
render() {
const { x, y } = this.body.position;
this.elem.style.top = `${y - this.h / 2}px`;
this.elem.style.left = `${x - this.w / 2}px`;
this.elem.style.transform = `rotate(${this.body.angle}rad)`;
},
};
Body.rotate(item.body, Math.random() * 360);
Composite.add(world, [item.body]);
(function rerender() {
item.render();
requestAnimationFrame(rerender);
})();
});
const ground = Bodies.rectangle(
fallbox.offsetWidth / 2,
fallbox.offsetHeight,
2000,
1,
{
isStatic: true,
}
);
const left = Bodies.rectangle(
0,
fallbox.offsetHeight / 2,
1,
fallbox.offsetHeight,
{
isStatic: true,
}
);
const right = Bodies.rectangle(
fallbox.offsetWidth,
fallbox.offsetHeight / 2,
1,
fallbox.offsetHeight,
{
isStatic: true,
}
);
Composite.add(world, [ground, left, right]);
const mouseConstraint = MouseConstraint.create(engine, {
element: fallbox,
constraint: {
stiffness: 0.2,
},
});
mouseConstraint.mouse.element.removeEventListener(
"mousewheel",
mouseConstraint.mouse.mousewheel
);
mouseConstraint.mouse.element.removeEventListener(
"DOMMouseScroll",
mouseConstraint.mouse.mousewheel
);
Composite.add(world, mouseConstraint);
Render.lookAt(render, {
min: { x: 0, y: 0 },
max: { x: fallbox.offsetWidth, y: fallbox.offsetHeight },
});
},
},
};
.fallbox {
position: relative;
height: 100vh;
width: 100%;
margin: auto;
background: black;
overflow: hidden;
.fallbox-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 95%;
max-width: 1050px;
z-index: 2;
// -khtml-user-select: none;
// -moz-user-select: none;
// -ms-user-select: none;
// user-select: none;
// pointer-events: none;
h1 {
font-size: 160px;
font-weight: 500;
line-height: 140px;
margin-bottom: 150px;
text-align: center;
color: white;
}
}
.fallbox-scene {
height: 100%;
width: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
contain: strict;
.item {
height: 120px;
width: 120px;
background: red;
position: absolute;
opacity: 0;
user-select: none;
will-change: transform;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
}
}
}
activated() {
this.startFallbox()
}
Use the activated hook to restart the animation. The code when mounted() is still needed.
I assume the problem is that when you navigate away and you some back the initial animation is finished, but as Nuxt caches some pages they are served from cache and therefore the mounted() hook is not called. This is where the activated() hooks comes in. It's called when a page/component was keept alive and is reactivated.

How to use custom fonts in TinyMCE using tinymce-vue package for VueJS?

I'm trying to use custom fonts stored in my assets/fonts folder with TinyMCE, but it seems like it can't render the font, except for the format selector. The content doesn't display the font correctly, although the font selector shows the font is being applied (in the title, for example).
Here's the code so far:
<template>
<tinymce-editor
:key="id"
:initial-value="initialValue"
:resize="false"
:init="{
selector: 'textarea#format-custom',
height: height,
plugins: 'table wordcount link lists',
menubar : false,
statusbar : false,
toolbar: 'undo redo | bold italic| styleselect | alignleft aligncenter alignright alignjustify | numlist bullist | fontselect',
content_css: [ '//www.tiny.cloud/css/codepen.min.css' ],
content_style: 'body { font-family: Roboto Light; font-size: 16px; }' + '.left { text-align: left; }' + 'img.left { float: left; }' + 'table.left { float: left; }' + '.right { text-align: right; }' + 'img.right { float: right; }' + 'table.right { float: right; }' + '.center { text-align: center; }' + 'img.center { display: block; margin: 0 auto; }' + 'table.center { display: block; margin: 0 auto; }' + '.full { text-align: justify; }' + 'img.full { display: block; margin: 0 auto; }' + 'table.full { display: block; margin: 0 auto; }' + '.bold { font-weight: bold; }' + '.italic { font-style: italic; }' + '.underline { text-decoration: underline; }' + '.title { font-family: Raleway Bold; font-size: 26px; }' + '.subtitle { font-family: Roboto Medium; font-size: 20px; }',
formats: {
alignleft: { selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'left' },
aligncenter: { selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'center' },
alignright: { selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'right' },
alignfull: { selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'full' },
bold: { inline: 'span', classes: 'bold' }, italic: { inline: 'span', classes: 'italic' },
titleformat: { inline: 'span', attributes: { title: 'Title'} , classes: 'title', },
subtitleformat: { inline: 'span', attributes: { title: 'SubTitle'} , classes: 'subtitle' } },
style_formats: [ { title: 'Title', format: 'titleformat' }, { title: 'SubTitle', format: 'subtitleformat' } ]
}"
api-key="no-api-key"
model-events="change keydown blur focus paste"
#input="handleInput"
#error="handleError"
/>
</template>
<script>
import Editor from '#tinymce/tinymce-vue'
export default {
components: {
'tinymce-editor': Editor
},
props: {
initialValue: {
type: String,
default: null
},
id: {
type: String,
default: null
},
height: {
type: String,
default: '100%'
}
},
methods: {
handleInput (value) {
this.$emit('input', value)
},
handleError (err) {
console.error(err)
}
}
}
</script>
Here's a print:
If you want to use custom fonts you need to:
Load them into TinyMCE via content_css
Include the fonts via the font_formats configuration option: https://www.tiny.cloud/docs/configure/editor-appearance/#font_formats
You appear to be loading the CSS from the TinyMCE demo site:
content_css: [ '//www.tiny.cloud/css/codepen.min.css' ],
This is likely not something you want to do as our demo CSS would likely not be appropriate for your web site/application. I would change that to use an appropriate CSS for your site. In that CSS you can load a custom font. For example:
#import url('https://fonts.googleapis.com/css?family=Lato');
Note: The reason the TinyMCE menu can render the font is you are likely loading the font on the page that includes TinyMCE but not in TinyMCE itself. The editor content is in its own iframe but the menus are part of the main page. If you inspect the DOM you will be able to see this layout. Using content_css allows you to inject CSS into the editor's iframe.

Nuxt / Vuex / Vue Reactivity Issue Increment

Hi everyone I am I having some difficulty when working with Nuxt and Vuex.
I am trying to run through the example Vuex / Nuxt Classic Mode.
https://nuxtjs.org/guide/vuex-store/
After clicking my increment button I dont see the number go up. My page just stays at 0, I can see within the console that the state knows the number is no longer 0 but not on the screen, as if it doesnt know to be reactive.
My assumption is that I have miss configured something somewhere and my 0 is not the actual state, but I created some copy of it somehow.
Here is my button within my template.
<button #click="inc">{{ counter }}</button>
Here is my inc function within my methods.
inc () {
this.$store.commit('increment')
},
Here is my computed
computed: {
counter () {
return this.$store.getters.counter
}
}
Here is my Vuex/index.js file contained within the store folder.
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
getters: {
counter: state => state.counter
},
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
Update: Included more code snippets, and replied to existing comments.
#Boussadjra Brahim #xaviert, thank you both for weighing in, I appreciate the assistance.
#Boussadjra Brahim - Yes, I had tried using an action that called the mutation, that didnt seem to get me there either. I also tried adjusting the state via the action alone, and wasnt able to make any changes, however that seems correct, as I am under the impression that actions call mutations to make state changes and do not themselves do so, please correct me if you know more. I am 100% open to the idea that I did not attempt it correctly. Below is that action that didnt do anything and the one that called the mutation
actions: {
increment (state) {
state.counter++
}
},
And here is the version with the action calling the mutation.
actions: {
incrementCounterUp () {
this.commit('increment')
}
},
#xaviert - I have tried starting the server over, and have also tried to see if an nuxt build followed by a firebase serve, to see if maybe that helped. It did not. My normal server start is 'npm run dev'. In hopes that you/anyone else may be able to find my mistake below is my full _id.vue component and also my nuxt.config.js file as maybe that's it. Its still pretty raw and could use a lot of refactoring so hope you can sort through it well enough.
_.id.vue
<template>
<div class="product">
<div class="product-image">
<div class="product-image-img">
<img v-bind:src="product.image_file" width="450px;"/>
</div>
</div>
<div class="product-details-wrapper">
<div class="product-details">
<h1>
<div v-if="this.$route.query.editPage">
<textarea #input="updateTextArea" ref="textarea2" v-model="product.item_name" type="text" />
</div>
<div v-else>{{product.item_name}}</div>
</h1>
<div class="product-description">
<div class="product-description-text" v-if="this.$route.query.editPage">
<textarea #input="updateTextArea" ref="textarea" v-model="product.description" type="text" />
</div>
<div class="product-description-text" v-else v-html="product.description"></div>
</div>
<p class="product-brand"><strong>Brand - </strong> {{product.brand_name}}</p>
<hr />
<div class="product-price">
<div v-if="this.$route.query.editPage">
<strong>Original Price - </strong>
<input v-model="product.msrp" type="text" />
</div>
<div v-else class="product-msrp">
<strong>Original Price - </strong>
<span class="strike">${{product.msrp}}</span>
</div>
<div v-if="this.$route.query.editPage">
<strong>Sale Price - </strong>
<input v-model="product.price" type="text" />
</div>
<div v-else class="product-sale-price">
<strong>Sale Price - </strong>
<span class="">${{product.price}}</span>
</div>
<div class="product-price">
Quantity x
<input #input="updateQuantity" v-model="quantity" min="1" class="" type="number" value="1" />
</div>
<button #click="inc">{{ counter }}</button>
</div>
</div>
</div>
<div v-if="this.$route.query.editPage" class="update-product"> <button #click="updateProduct(product)">Update</button></div>
<div class="footer">
<router-link to="/privacy-policy" target="_blank">Privacy</router-link> |
<router-link to="/terms" target="_blank">Terms</router-link>
</div>
</div>
</template>
<script>
// # is an alias to /src
import firebase from '#/services/fireinit'
import foo from '#/components/foo'
const db = firebase.firestore()
export default {
name: 'ProductPage',
head () {
return {
title: this.product.item_name
}
},
components: {
foo
},
data: function () {
return {
product: {},
image: '',
name: 'Checkout',
description: '',
currency: 'USD',
amount: '',
msrp: '',
quantity: 1
}
},
methods: {
inc () {
this.$store.dispatch('incrementCounterUp', true)
},
updateProduct: function (product) {
db.collection('products').doc(product.item_id).set(product)
.then(function () {
console.log('Document successfully written!')
})
.catch(function (error) {
console.error('Error writing document: ', error)
})
},
updateQuantity () {
this.product.msrp = (this.quantity * this.product.orgMsrp)
this.product.msrp = Math.round(100 * this.product.msrp) / 100
this.product.price = this.quantity * this.product.orgPrice
this.product.price = Math.round(100 * this.product.price) / 100
},
updateTextArea () {
this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
}
},
async asyncData({app, params, error}) {
const ref = db.collection("products").doc(params.id)
let snap
let thisProduct = {}
try {
snap = await ref.get()
thisProduct = snap.data()
thisProduct.orgMsrp = thisProduct.msrp
thisProduct.orgPrice = thisProduct.price
} catch (e) {
// TODO: error handling
console.error(e)
}
return {
product: thisProduct
}
},
mounted () {
if(this.$refs.textarea) {
this.$refs.textarea.style.minHeight = this.$refs.textarea.scrollHeight + 'px'
this.$refs.textarea2.style.minHeight = this.$refs.textarea2.scrollHeight + 'px'
}
},
computed: {
counter () {
return this.$store.getters.counter
}
}
}
</script>
<style lang="less">
body {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
margin: 0
}
p{
margin-top: 1em;
margin-bottom: 1em;
}
html, body, #__nuxt, #__layout, .default, .product{
height: 100%;
}
.product {
justify-content: center;
display: flex;
max-width: 1150px;
margin: 0 auto;
flex-wrap: wrap;
align-items: center;
padding: 0 24px;
&-price{
input {
border: 1px solid;
padding: 0 .3em;
text-align: center;
width: 50px;
}
}
}
.product-details{
width: 100%;
textarea {
width: 100%;
font-size: inherit;
color: inherit;
font-family: inherit;
font-weight: inherit;
height: initial;
resize: none;
background-color: transparent;
border: none;
}
h1{
font-size: 1.9rem;
margin: 15px 0 20px;
}
hr{
width: 50%;
margin: .5rem 0px;
}
p{
}
}
.product-description-text{
margin: 10px 0;
}
.product-image, .product-details-wrapper{
align-items: center;
display: flex;
justify-content: center;
}
.product-details-wrapper{
flex: 0 1 535px;
}
.product-image{
flex: 0 1 535px;
img{
width: 100%;
}
}
.product-price{
.strike{
text-decoration: line-through;
}
button{
display: flex;
width: 150px;
height: 50px;
border-radius: 5px;
justify-content: center;
font-size: 24px;
margin-top: 20px;
&:hover{
cursor: pointer;
background-color: #f1f1f1;
box-shadow: 3px 3px 11px -1px rgba(0, 0, 0, 0.48);
}
}
}
.product-sale-price{
color: #f30000;
}
.footer {
flex: 1 1 100%;
text-align: center;
color: #ccc;
margin-top: 25px;
padding: 15px;
a {
color: #ccc;
text-decoration: none;
&:hover{
text-decoration: underline;
}
}
}
.update-product{
position: absolute;
top: 0;
text-align: center;
}
</style>
nuxt.confgs.js
const pkg = require('./package')
const { STRIPE_TOKEN } = process.env;
module.exports = {
vue: {
config: {
productionTip: false,
devtools: true
}
},
buildDir: './functions/nuxt',
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: pkg.name,
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
],
/*
** Plugins to load before mounting the App
*/
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://github.com/nuxt-community/axios-module#usage
'#nuxtjs/axios',
'nuxt-stripe-module'
],
stripe: {
version: 'v3',
publishableKey: 'pk_test_XXX',
},
/*
** Axios module configuration
*/
axios: {
// See https://github.com/nuxt-community/axios-module#options
},
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
publicPath: '/public/',
vendor: [],
extractCSS: true,
bable: {
presets: [
'es2015',
'stage-8'
],
plugins: [
['transform-runtime', {
'polyfill': true,
'regenerator': true
}]
]
},
extend (config, { isDev }) {
if (isDev && process.client) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
},
router: {
middleware: 'router-auth'
}
},
plugins: [
{ src: '~/plugins/fireauth', ssr: true }
]
}
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
actions: {
incrementCounterUp () {
this.commit('increment')
}
},
getters: {
counter: state => state.counter
},
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
At the end of the day, I was not able to identify exactly what in my application was the error.
I assume that my during my initialization, configuration or development I touched something that should not have been touched, installed something that should not have be installed, messed with a package I should not have or was to bold in my nuxt.config.js changes.
I created a new nuxt app following the same install instructions. https://nuxtjs.org/guide/installation/
Moved the above _id.vue component exactly as it is and once I got dependencies updated it worked perfectly as seen in the image below.
Thank you very much #Boussadjra Brahim, #xaviert, #Andrew1325 for you assistance.

Unexpected behaviour removing a child component (row)

Description:
I have a table with some products, each row is a custom vue <row> component.
Each element has a closing (removing) button that triggers the custom "remove" event. The main app listens to this event and removes the children (by index)
The row a part from some static text it contains an input with a number.
The problem:
The parent (Vue app) removes the row, but the value of the input is then moved (and replaces its previous value) to the input in the next row.
Expected behaviour:
I want to simply remove the item I do not care about the value of the text input once it's removed. It should not move its value to the next sibling.
I attach an example.
let row = Vue.component('row', {
name: 'row',
props: ['number', 'name', 'sq'],
data: () => ({
quantity: 0
}),
template: '<tr>' +
'<td>{{number}}</td>' +
'<td>{{name}}</td>' +
'<td><button v-on:click="quantity--">-</button><input type="text" :value="quantity"><button v-on:click="quantity++">+</button></td>' +
'<td><button v-on:click="remove">×</button></td>' +
'</tr>',
methods: {
remove: function() {
this.$emit('remove', this.quantity)
}
},
beforeMount() {
this.quantity = this.sq
}
})
new Vue({
el: "#app",
data: {
out: [],
rows: [{
name: "Icecream",
sq: 0
},
{
name: "Sugar cube",
sq: 50
},
{
name: "Peanut butter",
sq: 0
},
{
name: "Heavy cream",
sq: 0
},
{
name: "Cramberry juice",
sq: 0
}
]
},
methods: {
removeRow: function(index, quantity) {
this.out.push(`Removing row ${index} (${this.rows[index].name} | ${quantity} units)`)
this.rows.splice(index, 1)
}
},
computed: {
log: function() {
return this.out.join("\r\n")
}
}
})
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
h2 {
font-weight: bold;
margin-bottom: 10px;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
td {
padding: 4px 5px;
}
input {
width: 40px;
text-align: center;
}
h4 {
margin-top: 20px;
margin-bottom: 5px;
}
#log {
padding: 10px;
background: #20262E;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<h2>Cart:</h2>
<table>
<row v-for="(row, index) in rows" :number="index" :name="row.name" :sq="row.sq" v-on:remove="removeRow(index, $event)"></row>
</table>
<h4>Log</h4>
<pre id="log" v-html="log"></pre>
</div>
As #Bert mentioned in the comments.
The problem was that I was missing a key.
https://v2.vuejs.org/v2/api/#key
Adding it solved the problem
Thanks

Vue js get parent property AFTER it's ready method has ran

I know I can use inherit to allow a child component to grab it's parent's properties, BUT the thing is.. is that I need to grab the property AFTER the parent ready method has ran. I'm having this issue everywhere in order to get width and height of parent components that are set in the ready method.
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
#testimonials {
width: 50%;
margin: 0 auto;
position: relative;
float: left;
min-height: 1px;
padding-left: 1.25rem;
padding-right: 1.25rem;
display: block;
}
h3 {
color: #b50937;
text-transform: uppercase;
margin: 0 0 20px;
font-size: 1.75rem;
}
.carousel {
position: relative;
overflow: hidden;
}
.carousel .slides {
overflow: hidden;
margin: 0 auto;
}
.carousel .slides .viewport {
overflow: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0);
transition: all 800ms cubic-bezier(0.77, 0, 0.175, 1);
transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
}
.carousel .slides .slide {
position: relative;
display: block;
float: left;
margin: 0 2px;
}
.carousel .slides .slide .box {
background-color: #d1dbe5;
box-sizing: border-box;
padding: 15px 20px;
}
.view-all {
text-align: right;
}
.arrows {
position: relative;
text-align: right;
width: 100%;
}
.arrows .arrow {
background-color: #d3d3d3;
color: #fff;
padding: 2px 13px;
position: static;
transition: 0.4s ease-in-out;
display: inline-block;
cursor: pointer;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.12.13/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="x-template" id="carousel">
<div class="carousel">
<div class="slides" v-style="viewport">
<div class="viewport" v-style="styles">
<content></content>
</div>
</div>
<div class="view-all">View all <i class="fa fa-angle-double-right"></i></div>
<div class="arrows">
<div class="arrow prev" v-on="click: prevSlide"><i class="fa fa-chevron-left"></i></div>
<div class="arrow next" v-on="click: nextSlide"><i class="fa fa-chevron-right"></i></div>
</div>
</div>
</script>
<script type="x-template" id="slide">
<div class="slide" v-style="styles">
<content></content>
</div>
</script>
<section id="testimonials">
<h3>What People Are Saying About Us</h3>
<carousel show="1" slide-margin="2">
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
</carousel>
</section><!-- END #TESTIMONIALS -->
Here is my Vue code since it's the only part that's relevant, although you can see what I'm having issues with upstairs ^^ (the snippet)
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
The reason I need to get it from the parent is because the clientWidth includes padding which I can't. So I can't do $(this.$el).width() in the data or computed properties data since $el is not available yet. From my child, I need to get this width AFTER the ready method has fired.
Thanks for any insight.
Without looking too closely at your code, my first thought to get parent data in the child is:
computed: {
val: this.$parent.val;
}
But I'm not certain that will work for you. Alternatively you might be able to change your parent's ready method to compiled so it runs before the child.