how to lazy load elements on demands depending on the page visited? - laravel

I am creating a Laravel project which embed many Vue components (using webpack+mix.js).
-In app.js I have:
import './bootstrap';
require('#fortawesome/fontawesome-free/js/all.js');
import Vue from "vue";
import router from './Router'
import store from './Store/index'
import vuetify from './vuetify.js'
import 'vuetify/dist/vuetify.min.css'
window.Vuetify = require('vuetify');
Vue.use(vuetify);
//import cartComponent from "./components/cartComponent";
// import cart from "./components/Cart";
import 'vuetify/dist/vuetify.min.css'
import Vuelidate from 'vuelidate'
Vue.use(Vuelidate)
import BTabs from 'bootstrap-vue'
import datePicker from "vue-bootstrap-datetimepicker";
//
Vue.use(datePicker);
Vue.use(BTabs)
const opts = {}
const my_components = document.getElementsByClassName("my-component-class-wrapper");
for (var i = 0; i <= my_components.length+1; i++) {
new Vue({
el: '#app' + i,
vuetify, //not all pages require it !
store, // *********************now store is shared between all the instances
router,
// opts,
components: {
cartComponent: () => import(/* webpackPrefetch: true */"./components/cartComponent"),
addToCart: () => import('./components/addToCart'), //in productDetail: <add-to-cart>
//cartComponent, //cart icon in navbar
cart: () => import('./components/Cart'),//cartDetails page
info: () => import('./components/Info') //info page
},
data: {},
async created() { //if removed the cart icon will disapear
store.dispatch('fetchProducts').then(_ => { //execute fetchProducts in vuex.
}).catch((error) => console.log(error))
},
validations: {}
});
}
I am using looping, so I can share one store between elements.
The problem is the slowness of the webpages to finish loading. And I discovered that #app0,#app1, .etc. are All carried to every page I visit, getting a message saying:Cannot find element: #app1,#app2,...
besides, not all the pages are using vuetify; another point, I don't need to fetch all the products in every page (async created()).
Is there a way to fetch elements on demand depending on the page I visit ? maybe that will solve the slowness of the pages.
The way the vue component are embedded in pages are :
-page1.blade.php :
<body>
<div id="app0" class="my-component-class-wrapper">
<info></info>
</div>
<script defer src="{{ mix('js/app.js') }}"></script>
</body>
-page2.blade.php:
<body>
<div id="app1" class="my-component-class-wrapper">
<add-to-cart></add-to-cart>
</div>
<script defer src="{{ mix('js/app.js') }}"></script>
</body>

Related

SweetAlert2 with Vue 3 and <script setup>

I have the Laravel/Inertia app and I use VueSweetAlert2 imported globally in app.js.
It works well on every component. But now, I want to use on the component and I can't find working solution for sweetalert. I've tried several ways, but sweetalert still doesn't work.
I tried:
const swal = inject($swal),
Import VueSweetAlert2 from 'vue-sweetalert2';
Import Swal from 'vue-sweetalert2';
Import swal from 'vue-sweetalert2';
and some other ways.
How can I use SweetAlert in <script setup>???
Thanks. Pato
<script setup>
import { inject } from 'vue'
const swal = inject('$swal')
function showDialog(event) {
swal.fire({
icon: 'success',
title: 'done',
showConfirmButton: false,
timer: 1500
});
}
</script>
Reference from
calling SweetAlert2 inside Async method in VUE 3

Laravel/Inertia how to register globally the Link component

I'm pretty new to Inertia (I have enough experience with Laravel), so I'm writting a toy SPA application. I learn that I must use the <Link ...> component instead of <a ...> to get the SPA behaivour. Problem is that I have to import the Link component on every other component that'll use links.
So, if I have a Page, I should do something like this:
<template>
...
<Link href="/about" class="...">
About Page
</Link>
...
</template>
<script>
import { Head, Link } from "#inertiajs/inertia-vue3";
export default {
components: {
Head,
Link,
},
...
};
</script>
And this works, but I think it's quite unefficient, boresome and so to have to import the Head and Link components for every page, after all a Link is the most common element on a page other than plan text.
Here https://inertiajs.com/releases/inertia-vue3-0.5.0-2021-07-13 in the documentation says you can register Link and Head components globally, so my app.js code looks like:
require("./bootstrap");
import { createApp, h } from "vue";
import { createInertiaApp } from "#inertiajs/inertia-vue3";
import { InertiaProgress } from "#inertiajs/progress";
import { Head, Link } from "#inertiajs/inertia-vue3";
const appName =
window.document.getElementsByTagName("title")[0]?.innerText || "Laravel";
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => require(`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
createApp({ render: () => h(app, props) })
.use(plugin)
.component("InertiaHead", Head)
.component("InertiaLink", Link)
.mixin({ methods: { route } })
.mount(el);
},
});
As the documentation says, but this does nothing. When I comment the import ... and components section on my page component. It doesn't throw an error, but it doesn't display anything, not even the text.
Any idea?
You have registered your components as "InertiaLink" and "InertiaHead". If you do this, you must also name them that way in the vue files.
app.js
vue file

Making a vuetify autocomplete with composition api and remote api?

The problem is the following :
How do you manage to make an API call, using Vuetify autocomplete and the brand new composition api ?
It doesn't seem that different from Vue 2.
in main.js
import Vue from 'vue'
import VueCompositionApi from '#vue/composition-api'
import Vuetify from 'vuetify'
import App from './App.vue'
Vue.use(Vuetify)
Vue.use(VueCompositionApi)
Vue.config.productionTip = false
new Vue({
vuetify: new Vuetify({}),
render: h => h(App)
}).$mount('#app')
in App.vue
<template>
<div id="app" data-app>
<v-autocomplete
v-model="model"
:items="items"
item-text="first_name"
item-value="id"
label="Select a user..."
/>
</div>
</template>
<script>
import { ref, onMounted } from '#vue/composition-api'
export default {
setup() {
const model = ref(null)
const items = ref()
const getUsers = async () => {
const { data } = await (
await fetch('https://reqres.in/api/users')
).json()
items.value = data
}
onMounted(getUsers)
return {
model,
items,
}
}
}
</script>
I did it in a codesandbox
https://codesandbox.io/s/vuetify-autocomplete-basic-p6q9m?file=/src/components/HelloWorld.vue

Vue.js router view no components?

I am trying to make a vue SPA using vuex, vue-router & laravel for backend. I was separating our data on our app.js to try to reduce clutter and keep our code neat. When everything on one page it works as intended, loading the routes in the router. But when we separate the code to make it more modular into: app.js, boostrap.js, routes.js, and store.js
The components aren't loading in our router-view and we are able to see our RouterLink
app.js
// Require the bootstrapper
require('./bootstrap');
// Grab imports
import Store from './store';
import Router from './routes';
// Views
import App from './views/App';
// Create the application
const app = new Vue({
el: '#heroic',
components: { App },
store: Store,
router: Router
});
boostrap.js
// Imports
import Vue from 'vue';
import Axios from 'axios';
import Swal from 'sweetalert2';
// Add to window
window.Vue = Vue;
window.Axios = Axios;
// Add Axios headers
window.Axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.Axios.defaults.headers.common['Authorization'] = 'Bearer ' + 'token';
window.Axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
routes.js
// Imports
import Vue from 'vue';
import VueRouter from 'vue-router';
import Store from './store';
// Set to use
Vue.use(VueRouter);
// Views
import Hello from './views/Hello';
import Home from './views/Home/';
import UserIndex from './views/UserIndex';
// Create our routes
const routes = [
{
path: '/',
name: 'home',
component: Home,
},
{
path: '/hello',
name: 'hello',
component: Hello,
},
{
path: '/users',
name: 'users.index',
component: UserIndex,
}
];
// Create the router
const router = new VueRouter({
mode: 'history',
routes: routes,
scrollBehavior (to, from, saved) {
if (saved) {
return saved;
}
return { x: 0, y: 0};
}
});
// Before every request
router.beforeEach((to, from, next) => {
});
// After every request
router.afterEach((to, from, next) => {
});
// Export
export default router;
hello.vue
<template>
<div class="row row-cards row-deck">
<div class="col-lg-4 col-md-6">
<p>Hello World!</p>
</div>
</div>
</template>
store.js
// Imports
import Vue from 'vue';
import Vuex from 'vuex';
import PersistedState from 'vuex-persistedstate';
import Cookie from 'js-cookie';
// Set use
Vue.use(Vuex);
// Create our store
const store = new Vuex.Store({
state: {
auth: [{
id: 1,
username: '',
motto: '',
rank: 1,
permissions: [],
token: ''
}],
users: [],
},
mutations:{
},
actions: {
},
getters: {
}
});
// Export
export default store;
The expected result is that when I visit the "/hello" route it would show the information that says "Hello world!" that is within the Vue file specified as the component in the routes section of the router. Instead using my Vue DevTools I get the following with no Hello world on the page.
https://i.pathetic.site/chrome_99Mbxf7f0c.png
My guess is the router is stuck waiting for the beforeEach (and also possibly afterEach) hook to be resolved. You need to call next().
Also unrelated, but if you’re using modules then you shouldn’t need to assign stuff on window.

Laravel 5.5 bootstrap error

I am getting below error.
Uncaught Error: Bootstrap's JavaScript requires jQuery. jQuery must be
included before Bootstrap's JavaScript.
app.js
require('./bootstrap');
window.Vue = require('vue');
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);
import App from './App.vue';
import Login from './components/Login.vue';
import Register from './components/Register.vue';
import Activity from './components/Activity.vue';
import SelectPersons from './components/SelectPersons.vue';
const routes = [
{
name: 'Login',
path: '/',
component: Login
},
{
name: 'Register',
path: '/register',
component: Register
},
{
name: 'Activity',
path: '/activity',
component: Activity
},
{
name: 'SelectPersons',
path: '/selectpersons',
component: SelectPersons
}
];
const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');
bootstrap.js
window._ = require('lodash');
/**
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
* for JavaScript based Bootstrap features such as modals and tabs. This
* code may be modified to fit the specific needs of your application.
*/
try {
window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');
} catch (e) {}
window.Vue = require('vue');
/**
* We'll load the axios HTTP library which allows us to easily issue requests
* to our Laravel back-end. This library automatically handles sending the
* CSRF token as a header based on the value of the "XSRF" token cookie.
*/
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
/**
* Next we will register the CSRF Token as a common header with Axios so that
* all outgoing HTTP requests automatically have it attached. This is just
* a simple convenience so we don't have to attach every token manually.
*/
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
/**
* Echo exposes an expressive API for subscribing to channels and listening
* for events that are broadcast by Laravel. Echo and event broadcasting
* allows your team to easily build robust real-time web applications.
*/
// import Echo from 'laravel-echo'
// window.Pusher = require('pusher-js');
// window.Echo = new Echo({
// broadcaster: 'pusher',
// key: 'your-pusher-key'
// });
Here is the file that loads every vue component or blade template pages.
<html>
<head>
{{Html::style('/css/bootstrap.css')}}
{{Html::style('/css/style.css')}}
{{Html::script('/js/bootstrap.js')}}
</head>
<body>
<div id="app">
</div>
<script src="{{asset('js/app.js')}}"></script>
</body>
</html>
I am using Laravel with vue. Can anybody help me to solve this issue?
Thanks
Your app.js contains jquery. so do as the error says and load bootstrap after jquery.
<html>
<head>
{{Html::style('/css/bootstrap.css')}}
{{Html::style('/css/style.css')}}
</head>
<body>
<div id="app">
</div>
<script src="{{asset('js/app.js')}}"></script>
{{Html::script('/js/bootstrap.js')}}
</body>
</html>
Bootstrap required jQuery to run some of its features like the dropdown. the error says "Uncaught Error: Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.". So first, require the jquery library, then next is the bootstrap.min.js or bootstrap.js. Please feel free to comment if you have any problem with this. And one more thing, it is better to place your all JS files before </body>.
Try this
<html>
<head>
{{Html::style('/css/bootstrap.css')}}
{{Html::style('/css/style.css')}}
</head>
<body>
<div id="app">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
{{Html::script('/js/bootstrap.js')}}
<script src="{{asset('js/app.js')}}"></script>
</body>
</html>

Resources