How to load Axios Response before Vue Component renders? - ajax

I want to use:
homePage.image = 'storage/' + 'rkiGXBj7KJSOtsR5jiYTvNOajnzo7MlRAoXOXe3V.jpg'
inside:
<div class="home-image" :style="{'background-image': 'url(' + homePage.image + ')'}"></div>
before the Vue Component is rendered but homePage.image returns "".
This is my component:
<template>
<section id="home" class="home">
<div class="image-container">
<div class="home-image" :style="{'background-image': 'url(' + homePage.image + ')'}"></div>
</div>
</section>
</template>
<script setup>
import {ref} from 'vue';
const homePage = ref({
image: ""
});
axios.get('/home')
.then(res => {
homePage.image = 'storage/' + 'rkiGXBj7KJSOtsR5jiYTvNOajnzo7MlRAoXOXe3V.jpg'; // storage link + image file name
})
.catch(err => {
console.log(err.response);
});
// works
// const image = 'storage/' + 'rkiGXBj7KJSOtsR5jiYTvNOajnzo7MlRAoXOXe3V.jpg';
</script>
How do I get homePage.image to update to 'storage/' + 'rkiGXBj7KJSOtsR5jiYTvNOajnzo7MlRAoXOXe3V.jpg' before it is loaded into the Component from inside the axios function?

When you use ref for reactivity you must use value:
homePage.value.image = 'storage/' + 'rkiGXBj7KJSOtsR5jiYTvNOajnzo7MlRAoXOXe3V.jpg';

Related

Alpinejs x-if is not being triggered

I have data that I am pulling from ajax. And I want this data display only when it is successfully pulled.
import Alpine from 'alpinejs'
import axios from 'axios'
const http = axios.create({
baseURL: 'url',
})
window.axios = http
window.Alpine = Alpine
document.addEventListener('alpine:init', () => {
Alpine.data('cart', () => ({
items: null,
init(){
window.axios.get('wc/store/cart')
.then(({data})=>{
this.items = data
console.log(this.items)
}).catch(error => {
console.log(error.toString())
})
},
}))
})
Alpine.start()
Now I am using this in my template
<div x-data="cart">
<template x-if="items">
<h1>Shopping Cart</h1>
<!-- display items here -->
</template
</div>
The thing is, the h1 element is displayed but not the data from ajax.
Am I doing anything wrong. I am pretty confidence this should work.
You're not displaying your items. Keep in mind that template tags require a single root element only.
<div x-data="card">
<template x-if="items">
<div>
<h1>Shopping Cart</h1>
<template x-for="item in items">
<div>
<h2 x-text="item.text"></h2>
</div>
</template>
</div>
</template>
</div>

Scrollspy Uikit 3 framework and count up

i am a beginer in frontend and javascript hard for me :( I want to make count numbers with component scrollspy uikit 3 without jquery https://getuikit.com/docs/scrollspy
I made like this, but it's not working
<span id="number"></span>
<script>
UIkit.scrollspy('#number', 'inview', function () {
const countUp = new CountUp('number', 0, 1000 );
countUp.start();
});
</script>
I created a script for this.
var util = UIkit.util;
var el = util.$('#heading');
var textIndex = 0;
UIkit.scrollspy(el, {repeat: true, delay: 100});
util.on(el,'inview', function (){
function counter( start, end, duration) {
let current = start,
range = end - start,
increment = end > start ? 1 : -1,
step = Math.abs(Math.floor(duration / range)),
timer = setInterval(() => {
current += increment;
el.textContent = current;
if (current == end) {
clearInterval(timer);
}
}, step);
}
counter(0, 100, 3000);
});
util.on(el, 'outview', function(){
el.textContent = 0;
});
<!-- UIkit CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit#3.6.22/dist/css/uikit.min.css" />
<!-- UIkit JS -->
<script src="https://cdn.jsdelivr.net/npm/uikit#3.6.22/dist/js/uikit.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/uikit#3.6.22/dist/js/uikit-icons.min.js"></script>
<section class="uk-section uk-section-primary" uk-height-viewport="offset-top: true">
<div class="uk-container">
<div class="uk-text-center">
<h1 >SECTION 1</h1>
Source Code for Number Increment
</div>
<div class="uk-text-center uk-margin-medium-top">
<a class="uk-link-reset" href="#section" uk-scroll>Scroll</a>
</div>
</div>
</section>
<section class="uk-section uk-section-secondary" id="section">
<div class="uk-container">
<h1 class="uk-text-center" id="heading">0</h1>
</div>
</section>
You need to listen inview and outview event. Here is the method:
UIkit.util.on(element, 'event', function(){
//your code will be here here
});

Unknown custom element: <app-home> - did you register the component correctly? For recursive components, make sure to provide the "name" option

I have this problem but i try some solutions in web but and i can't resolve it: Unknown custom element:
- did you register the component correctly? For recursive components, make sure to provide the "name" option.
The problem appears to be in those fils :
Please I need help as soon as possible
routes.js:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../components/Home.vue";
import PostDetails from "../components/PostDetails.vue";
Vue.use(VueRouter);
const routes = [{
path: "/",
component: Home,
name: "Home"
},
{
path: "/post/:slug",
component: PostDetails,
name: "postDetails"
}
];
const router = new VueRouter({
routes: routes,
hashbang: false,
mode: "history"
});
export default router;
app.js:
import Vue from "vue";
import VueRouter from "vue-router";
require('./bootstrap');
window.Vue = require('vue');
Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('app-home', require('./AppHome.vue'));
import router from "./routes/routes.js";
const app = new Vue({
el: '#app',
vuetify,
render: h => h(App),
router: router,
});
AppHome.vue:
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
export default {
};
</script>
Home.vue:
<template>
<div class="container">
<div class="row my-4">
<div class="col-md-8">
<div class="card">
<div class="card-header">Articles</div>
<div
class="card-body"
:key="index"
v-for="(post, index) in posts.data"
>
<div class="media">
<img
:src="post.photo"
class="rounded img-fluid mr-2 shadow-sm"
alt=""
srcset=""
/>
<div class="media-body text-justify">
<router-link :to="post.path">
<h3>{{ index }}:{{ post.title }}</h3>
</router-link>
<p>
<span class="textdefaut">
{{ post.user.name }}
</span>
<span class="text-danger">
{{ post.added }}
</span>
</p>
<p class="lead text-justify">
{{ post.body.substr(0, 200) }}...
</p>
<hr />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
posts: {},
};
},
created() {
this.getPosts();
},
methods: {
getPosts() {
axios
.get("/api/posts")
.then((response) => {
console.log(response.data);
this.posts = response.data;
})
.catch((err) => console.log(err));
},
},
};
</script>
Post Details:
<template>
<div>
Posts details , This shows that the route is really working!!
<router-link to="/Home"><a>Back to the root</a></router-link>
</div>
</telpmate>
<script>
export default {
data () {
return {
message: 'Hoera!!!!'
};
}
};
</script>
If all of your Vuejs components (including AppHome.vue) are in /resources/js/components directory, you must change:
Vue.component('app-home', require('./AppHome.vue'));
by
Vue.component('app-home', require('./components/AppHome.vue'));
...in your app.js
Try to append .default option:
Vue.component('app-home', require('./components/AppHome.vue').default);

Laravel 6 + Vue.js Failed to mount component: template or render function not defined

Perhaps someone could help me? I'm trying to create a little chat app from here and I am have trouble displaying the Vue components.
The dev tools console gives me:
Failed to mount component: template or render function not defined.
I am using Laravel 6
Appreciate any help on this one! thanks :)
I have tried deleting the node_modules folder and rebuilding, after adding .default - with no luck.
app.js
require('./bootstrap');
window.Vue = require('vue');
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Vue.component('chat-messages', require('./components/ChatMessages.vue').default);
Vue.component('chat-form', require('./components/ChatForm.vue').default);
import Vue from 'vue'
const app = new Vue({
el: '#app',
data: {
messages: []
},
created() {
this.fetchMessages();
Echo.private('chat')
.listen('MessageSent', (e) => {
this.messages.push({
message: e.message.message,
user: e.user
});
});
},
methods: {
fetchMessages() {
axios.get('/messages').then(response => {
this.messages = response.data;
});
},
addMessage(message) {
this.messages.push(message);
axios.post('/messages', message).then(response => {
console.log(response.data);
});
}
}
});
and my two components:
ChatForm.vue
<template>
<div class="input-group">
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Type your message here..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
Send
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: ''
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
this.newMessage = ''
}
}
}
</script>
ChatMessage.vue
<template>
<ul class="chat">
<li class="left clearfix" v-for="message in messages" v-bind:key="message">
<div class="chat-body clearfix">
<div class="header">
<strong class="primary-font">
{{ message.user.name }}
</strong>
</div>
<p>
{{ message.message }}
</p>
</div>
</li>
</ul>
</template>
<script>
export default {
props: ['messages']
};
</script>
This might help you to solve your problem, if not just tell me to find new solution. first remove this in your app.js
const files = require.context('./', true, /\.vue$/i)
files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
Next, remove also this code, you already imported vue twice.
import Vue from 'vue'

Passing data around single file components in Vue files?

I have data in my Topbar.vue file called activeTab that I want the value of to drive other components in my blade view but right now it's only in my Topbar.vue component.
main-page-blade.php
<div id = "app">
<Topbar>dsd</Topbar>
**** wanting to do something like this: ****
<Account v-if="activeTab === 1"></Account>
<Names v-if="activeTab === 2"></Names>
********************************************
</div>
<script type="text/javascript" src="dist/app.js">
app.js
window.Vue = require('vue');
Vue.component('topbar', require('./components/Topbar.vue').default);
export const bus = new Vue();
new Vue({
el: "#app"
})
Topbar.vue
<template>
<div class="cont">
<div class="tabs">
<a v-on:click="handleClick(1)" v-bind:class="[ activeTab === 1 ? 'active' : '' ]">Names</a>
<a v-on:click="handleClick(2)" v-bind:class="[ activeTab === 2 ? 'active' : '' ]">Order</a>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeTab: 1
}
},
methods: {
handleClick: function(num) {
this.activeTab = num
}
}
</script>
Put the management of activeTab inside the data() of your parent component.
To pass data from child to its parent, we use custom events.
So, in your Topbar.vue, you can implement handleClick like:
handleClick: function(num) {
this.$emit('click-from-topbar', num)
}
And then you will be able to catch this event in your main page doing:
<Topbar #click-from-topbar="someMethod">dsd</Topbar>
Finally, you do what you need inside the parent component (main page), using:
someMethod: function(num) {
this.activeTab = num
}

Resources