Vue 2 - How to instantiate properly, at the right time - vue.js

One of the vue's instance of my app seems to instantiate too early. Even with a document.addEventListener('DOMContentLoaded', ...). As a consequence, I noticed that the event listeners aren't properly binded. A simple #click="test" (where test references to a console.log) didn't work.
Below, see the code where the #click doesn't work. It is a component located in a vue instance, instanciated on DOMContentReady :
const navBurger = {
template: `
<nav class="burgerNav"">
<button class="burgerNav__icon" #click="test">
</button>
</nav>
`,
methods: {
test: function() {
console.log('test')
}
}
}
export default navBurger
I "solved" the problem by adding a little timeout (200ms) before instanciation to the root instance of this component but it seems a messy and fragile solution. Is there any clean way to instantiate at the exact right time ? I need this instance to be ready as quick as possible because it contains the navigation located in the header.
Below, find the loading order of the js files. Targetted file is assets/js/components/nav/nav.js. However changing this order doesn't solve the problem.
<!--========== VUE ==========-->
<script src="<?= url('assets') ?>/js/libraries/vue.js"></script>
<!--========== SCRIPTS ==========-->
<script src="<?= url('assets') ?>/js/components/nav/nav.js" type="module" defer></script>
<script src="<?= url('assets') ?>/js/shop.js" type="module" defer></script>
<script src="<?= url('assets') ?>/js/script.js" type="module" defer></script>
<script src="https://js.stripe.com/v3/" defer></script>

Related

VueJS: Call function from bootstrap/jQuery script includes in template/layout from a component

i am very new to VueJS and want to build an Admin Dashboard for an existing bootstrap template (SB Admin Pro). I know there is a BootstrapVUE but we want to use the specified template that we purchased before. So this is not an option for me/us.
My Goal:
In our vue component we make an axios call to our backend to retrieve and show some data. If the call fails we want to call in the catch block a bootstrap function for toast to show some notification to the user (like: Error while fetching data from backend...). We included the bootstrap and jquery libraries from the template in the default index.html.
The Problem:
I don't know how to call the toasts (or other) functions from the vue component. In the template the call looks like this:
$("#toastBasic").toast("show");
Our index.html looks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="svote UG (haftungsbeschränkt)" />
<script data-search-pseudo-elements defer src="js/font-awesome-5.11.2.min.js" crossorigin="anonymous"></script>
<script src="./js/feather.min.js" crossorigin="anonymous"></script>
</head>
<body class="nav-fixed">
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app">
</div>
<!-- built files will be auto injected -->
<script defer src="js/jquery-3.4.1.min.js" crossorigin="anonymous"></script>
<script defer src="js/bootstrap.min.js" crossorigin="anonymous"></script>
<script defer src="js/script.js"></script>
</body>
</html>
Our vue component:
<template>
<main>
<div style="position: absolute; top: 1rem; right: 1rem;">
<!-- Toast container -->
<div style="position: absolute; bottom: 1rem; right: 1rem;">
<!-- Toast -->
<div class="toast" id="toastBasic" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
<div class="toast-header">
<i data-feather="bell"></i>
<strong class="mr-auto">Toast with Autohide</strong>
<small class="text-muted ml-2">just now</small>
<button class="ml-2 mb-1 close" type="button" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="toast-body">This is an example toast alert, it will dismiss automatically, or you can dismiss it manually.</div>
</div>
</div>
</div>
<ContentHeader title="Blank" icon="fas fa-file" subtitle="A blank page to get you started!" />
<div class="container-fluid mt-n10">
<div v-if="error" class="alert alert-danger" role="alert">
{{ error }}
</div>
<div class="row">
<Card cHeader="Eine Karte" class="col-md-12"> {{ contacts }}</Card>
</div>
</div>
</main>
</template>
<script>
import ContentHeader from '../../components/ContentHeader'
import Card from '../../components/Card'
import axios from 'axios';
export default {
name: "Contact",
components: {
ContentHeader,
Card,
},
data() {
return {
contacts: null,
error: null
}
},
mounted() {
const url = 'http://localhost:3000/v1/';
axios.get(url + 'contsact')
.then(response => {
this.contacts = response.data
console.log(response)}
)
.catch(error => {
console.log(error.response)
$("#toastBasic").toast("show");
});
}
}
</script>
In vue.config.js, specify jquery as external (this tells webpack where to provide jquery from when it's imported in any component):
configureWebpack: {
externals: {
jquery: 'window.jQuery'
}
}
Place all the <script>s you want loaded by the time Vue inits in your public/index.html page, in the <head> tag and remove their defer attribute. This includes any jquery plugin (or anything requiring/extending jquery) you might want to use in your Vue app (in your case, bootstrap.min.js).
The above will make it work when developing (in serve). You'll need to do the same for prod: Load jquery and any dependency before initing the Vue app.
Now you can safely use
import * as $ from 'jquery'
in any component.
Webpack will place in $ whatever window.jQuery is at the moment the component inits.
The above approach makes sure all required scripts are loaded before Vue inits (which is a bit extreme, but it makes sure there's no way you can call the jquery method before its dependencies are loaded).
If you don't want to wait for jquery and bootstrap.min.js to load before you init your Vue app, a trick you could use is to assign jquery from window object just before you need it:
yourAlertMethod() {
const $ = window.jQuery;
$.toast()...
}
Obviously, you no longer have to move all the scripts in <head> and to remove their defer. This second method doesn't guarantee they would have already loaded before your method is first used. But your app inits faster.
Here's a basic example.
I used the second method, codesandbox.io doesn't have support for #vue/cli v3 hence vue.config.js doesn't work as in a Vue project created with vue create. Therefore, I had to use the second method.
The full list of dependecies you need to load before you call the $(el).toast() method:
bootstrap.min.css
jquery.js
popper.js
bootstrap.min.js
(see them in public/index.html). You can copy/paste them from Bootstrap.
You can get ref of the element and pass it to jQuery
<div ref="toast" class="toast" id="toastBasic" role="alert" aria-live="assertive" aria-atomic="true" data-delay="5000">
import $ from 'jQuery';
$(this.$refs.toast).toast("show");
I don't recommend that though.

How to make Sheety.co work inside the Vue.js component

The Sheety API is great but I cannot make it work with Vue.
The only included example uses jQuery with handlebars.js which, like vue.js, uses double mustache syntax that collides.
<html>
<head>
<title>UK Theme Parks</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.12/handlebars.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$.getJSON('https://api.sheety.co/uk-theme-parks', function(data) {
var template = Handlebars.compile($('#item-template').html())
$('#items').html(template(data))
})
})
</script>
<script id="item-template" type="text/x-handlebars-template">
<ul>
{{#each this}}
<li>{{name}}</li>
{{/each}}
</ul>
</script>
</head>
<body>
<div id="items">Loading theme parks...</div>
</body>
</html>
Is there a way to make this example work inside the Vue component? Most preferably, to make it work without having to import the handlebars.js or jQuery?
Please mind that I am an exploratory designer, not a well-versed js coder, so I would greatly appreciate a working example :)

How can I use Components in a VueJS2 CDN project?

I am pretty much stuck on it and I'm not even sure if what I was trying is possible.
Here's my project if needed:
https://drive.google.com/open?id=1lty3rzUs1h7Rtw5tsN92WeaTBJw2fqVy
Updated:
I'm not sure how to display it any better as this is the best it gets.. Basically im passing NestedComponent into Component which is getting passed into app.js which is rendering it into the index.html. That's it, for some reason doesn't work.
// "main.js" the Vue file that renders to the index.html
new Vue({
el: '#app',
components: { Component},
template: '<Component/>'
})
import Component from 'Component'
// "Component.vue" that is getting passed into the above "app.js"
<template lang="html">
<div>
<p>{{ title }}</p>
<h1>Hi!</h1>
<NestedComponent/>
</div>
</template>
<script>
import NestedComponent from 'NestedComponent'
export default {
name: 'Component',
components: {
NestedComponent
},
data: {
title: 'Hello'
}
}
</script>
// "NestedComponent.vue" a nested component that is getting passed onto it's parent Component "Component.vue"
<template lang="html">
<div>
<p>{{ im a nested component }}</p>
</div>
</template>
<script>
export default {
name: 'NestedComponent',
components: {
},
data: {
}
}
</script>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Vue</title>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
</head>
<body>
<div id="app">{{title}}</div>
<script type="text/javascript" src="/script.js"></script>
<script src="app.js"></script>
</body>
</html>
There are a few things that I think is causing the problem:
You are using .vue files. They require special loaders via
Webpack or similar tool. They will then be converted into a normal
.js file. In your case, you have a CDN version of Vue so these features will not be available to you.
As people have mentioned before the use of import and export is not supported by the browser natively. This again needs to run through the Webpack or similar tool.
Find similar information in the docs
https://v2.vuejs.org/v2/guide/single-file-components.html

Vue.js & bxslider, The slider doesn’t load. Any thoughts on how to fix it?

I am using browserify and i want to use bxslider. When i had all the templates in a single file (index.html), it was working. Now i am using browserify to build it so i have vue components. I want to use bx slider in a vue component.
slider.vue
<ul class="bxslider">
<li>
<img src="img/thumb-01.jpg"/>
</li>
</ul>
index.html
<link href="plugins/bxslider/jquery.bxslider.css" rel="stylesheet" />
<div id="app"></div>
<!-- scripts -->
<script src="plugins/jQuery/jQuery-2.2.0.min.js"></script>
<script src="plugins/bxslider/jquery.bxslider.min.js"></script>
<script src="dist/build.js"></script>
<script>
$(document).ready(function(){
$('.bxslider').bxSlider();
});
</script>
I couldn't get the bxslider, i try to use it as a function in a component, alse try to use it in a seperate file. Any suggestions please?
The problem is that $(document).ready() is executed before the vue.js code. You need to replace this code
$(document).ready(function(){
$('.bxslider').bxSlider();
});
with
$(document).ready(function(){
setTimeout(function(){
$('.bxslider').bxSlider();
},100);
});

Jquery Treeview plugin does not work in new mvc4 project

Im trying to run this plugin
https://github.com/jzaefferer/jquery-treeview
In clear html it works, so it means the problem is in my mvc code.
I have following code
<!-- TREEVIEW Plugin -->
<link href="/Content/jquery-treeview/jquery.treeview.css" rel="stylesheet" type="text/css" />
<script src="/Content/jquery-treeview/jquery-1.2.6.min.js" type="text/javascript"></script>
<script src="/Content/jquery-treeview/jquery.treeview.js" type="text/javascript"></script>
<script type="text/javascript">
$(function () {
$("#treeview ul").treeview();
});
</script>
the link addresses are okay, because they are not underlined and i checked the path manually. In clear HTML the plugin works. I also tried
#Scripts.Render("~/Content/jquery-treeview/jquery-1.2.6.min.js")
or
#Url.Content("~/Content/jquery-treeview/jquery-1.2.6.min.js")
At it seems same (not working). Where is the problem ?
But this code works, so JQuery is loaded.
$(document).ready(function () {
alert("ready!");
});
HTML Code
<div id="treeview">
<ul>
<li>Category
<ul><li>SubCategory</li></ul>
</li>
</ul>
</div>
Mystery revealed, in Shared/_Layout.cshtml JQuery was also included by default so the solution was comment it out :-)