Content Will Only Display After Reload - vue-router

I'm attempting to display a simple calendar based on the jsCalendar library. When I navigate to the page, the calendar won't appear; however, when I reload the page [⌘-R] or enter the page URL directly, the content appears normally. I've tested in Safari and FireFox and the behavior is the same.
Desired Outcome:
Display the content when the page is reached via Vue Router or direct navigation.
Calendar.vue
<template>
<div class="auto-jsCalendar black-theme"
data-navigator-position="right"
data-month-format="month YYYY"
data-day-format="DDD">
</div>
</template>
<script>
import 'simple-jscalendar'
export default {
emits: ['page-data'],
mounted() {
this.$emit('page-data', {title: 'calendar', content: '',})
},
}
</script>
<style>
#Import '~simple-jscalendar/source/jsCalendar.css';
#Import '~simple-jscalendar/themes/jsCalendar.darkseries.css';
</style>
Navigating to Calendar.vue
When navigating to the page, the div looks like this:
<div class="auto-jsCalendar black-theme" data-navigator-position="right" data-month-format="month YYYY" data-day-format="DDD"></div>
Reload or Direct Navigation
When reloading the page or entering the URL directly into the browser, the div looks like this:
<div class="auto-jsCalendar black-theme" data-navigator-position="right" data-month-format="month YYYY" data-day-format="DDD" jscalendar-loaded="true"></div>
(The dynamic attribute jscalendar-loaded (which is added to the div when the calendar object is displayed) is not established when navigating to the page.)
Environment:
Dave#[SNIP] my_spa % npm list
my_spa#0.1.33 /.../my_spa
├── #vue/cli-plugin-babel#4.5.15
├── #vue/cli-plugin-router#4.5.15
├── #vue/cli-plugin-vuex#4.5.15
├── #vue/cli-service#4.5.15
├── #vue/compiler-sfc#3.2.20
├── babel-eslint#10.1.0
├── chart.js#3.6.0
├── chartjs-plugin-annotation#1.1.0
├── chartjs-plugin-datalabels#2.0.0
├── core-js#3.19.0
├── eslint-plugin-vue#7.20.0
├── simple-jscalendar#1.4.4
├── vue-router#4.0.11
├── vue#3.2.20
├── vue3-smooth-dnd#0.0.2
├── vuex-persist#3.1.3
└── vuex#4.0.2
EDIT: In consulting with the author of jsCalendar, I've come to learn that the script acts on the page load event which explains why the content doesn't update when navigating to the view. The external script has an autoFind() function which could be called from mounted() which should update the content; however, I've been unable to find the right way to call the function.
import jsCalendar from 'simple-jscalendar'
mounted() {
jsCalendar.autoFind()
this.$emit('page-data', {title: 'calendar', content: '',})
},
results in:
Unhandled Promise Rejection: TypeError: simple_jscalendar__WEBPACK_IMPORTED_MODULE_0___default.a.autoFind is not a function.

I looked at the documentation from the link, here is what I would do:
remove the auto-jsCalendar from the div as this is the hook that makes it work when you load the page, but not when you navigate and add a ref.
Then in your mounted hook call the jsCalendar.new as documented here:
https://gramthanos.github.io/jsCalendar/docs.html (Javascript Create Calendar)
<template>
<div class="black-theme"
data-navigator-position="right"
data-month-format="month YYYY"
data-day-format="DDD"
ref="calendar">
</div>
</template>
<script>
import 'simple-jscalendar'
export default {
emits: ['page-data'],
mounted() {
jsCalendar.new(this.$refs.calendar)
this.$emit('page-data', {title: 'calendar', content: '',})
},
}
</script>
<style>
#Import '~simple-jscalendar/source/jsCalendar.css';
#Import '~simple-jscalendar/themes/jsCalendar.darkseries.css';
</style>
Though in the long run I'd suggest to look for a library that was built for Vue. It is always a bit tricky if a third party library manipulates the DOM that is also used from Vue.

Related

How to get all pages and components as object in nuxt js project

I have
pages/
index.vue
other.vue
components/
CustomButton.vue
CustomInput.vue
I need to get index.vue, other.vue, CustomButton.vue, CustomInput.vue as VueComponent object to access their data() variables.
I'm using Nuxt2.

VueJS, displaying static images vs. binding a function from methods [duplicate]

I'm looking for the right url to reference static assets, like images within Vue javascript.
For example, I'm creating a leaflet marker using a custom icon image, and I've tried several urls, but they all return a 404 (Not Found):
Main.vue:
var icon = L.icon({
iconUrl: './assets/img.png',
iconSize: [25, 25],
iconAnchor: [12, 12]
});
I've tried putting the images in the assets folder and the static folder with no luck. Do I have to tell vue to load those images somehow?
For anyone looking to refer images from template, You can refer images directly using '#'
Example:
<img src="#/assets/images/home.png"/>
In a Vue regular setup, /assets is not served.
The images become src="data:image/png;base64,iVBORw0K...YII=" strings, instead.
Using from within JavaScript: require()
To get the images from JS code, use require('../assets.myImage.png'). The path must be relative (see below).
So your code would be:
var icon = L.icon({
iconUrl: require('./assets/img.png'), // was iconUrl: './assets/img.png',
// iconUrl: require('#/assets/img.png'), // use # as alternative, depending on the path
// ...
});
Use relative path
For example, say you have the following folder structure:
- src
+- assets
- myImage.png
+- components
- MyComponent.vue
If you want to reference the image in MyComponent.vue, the path sould be ../assets/myImage.png
Here's a DEMO CODESANDBOX showing it in action.
A better solution would be
Adding some good practices and safity to #acdcjunior's answer, to use # instead of ./
In JavaScript
require("#/assets/images/user-img-placeholder.png")
In JSX Template
<img src="#/assets/images/user-img-placeholder.png"/>
using # points to the src directory.
using ~ points to the project root, which makes it easier to access the node_modules and other root level resources
In order for Webpack to return the correct asset paths, you need to use require('./relative/path/to/file.jpg'), which will get processed by file-loader and returns the resolved URL.
computed: {
iconUrl () {
return require('./assets/img.png')
// The path could be '../assets/img.png', etc., which depends on where your vue file is
}
}
See VueJS templates - Handling Static Assets
Right after oppening script tag just add import someImage from '../assets/someImage.png'
and use it for an icon url iconUrl: someImage
this finally worked for me, image passed as prop:
<img :src="require(`../../assets/${image}.svg`)">
What system are you using? Webpack? Vue-loader?
I'll only brainstorming here...
Because .png is not a JavaScript file, you will need to configure Webpack to use file-loader or url-loader to handle them. The project scaffolded with vue-cli has also configured this for you.
You can take a look at webpack.conf.js in order to see if it's well configured like
...
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
...
/assets is for files that are handles by webpack during bundling - for that, they have to be referenced somewhere in your javascript code.
Other assets can be put in /static, the content of this folder will be copied to /dist later as-is.
I recommend you to try to change:
iconUrl: './assets/img.png'
to
iconUrl: './dist/img.png'
You can read the official documentation here: https://vue-loader.vuejs.org/en/configurations/asset-url.html
Hope it helps to you!
It works for me by using require syntax like this:
$('.eventSlick').slick({
dots: true,
slidesToShow: 3,
slidesToScroll: 1,
autoplay: false,
autoplaySpeed: 2000,
arrows: true,
draggable: false,
prevArrow: '<button type="button" data-role="none" class="slick-prev"><img src="' + require("#/assets/img/icon/Arrow_Left.svg")+'"></button>',
Having a default structure of folders generated by Vue CLI such as src/assets you can place your image there and refer this from HTML as follows <img src="../src/assets/img/logo.png"> as well (works automatically without any changes on deployment too).
I'm using typescript with vue, but this is how I went about it
<template><div><img :src="MyImage" /></div></template>
<script lang="ts">
import { Vue } from 'vue-property-decorator';
export default class MyPage extends Vue {
MyImage = "../assets/images/myImage.png";
}
</script>
You could define the assets path depending on your environment
const dev = process.env.NODE_ENV != 'production';
const url = 'https://your-site.com';
const assets = dev ? '' : url;
<template>
<img :src="`${assets}/logo.png`"/>
<p>path: {{assets}}</p>
</template>
<script>
export default {
data: () => ({
assets
})
}
</script>
Ideally this would be inside an utils js file, or as an extended app defineProperty, like:
const app = createApp(component);
app.config.globalProperties.$assets = assets;
app.mount(element);
and will be available as:
<template>
<img :src="`${$assets}/logo.png`"/>
<p>path: {{$assets}}</p>
</template>
<script>
export default {
mounted() {
console.log(this.$assets);
}
}
</script>
load them in created, mounted or where you need them
async created() {
try {
this.icon = (await import('#assets/images/img.png')).default;
} catch (e) {
// explicitly ignored
}
and then
<img :src=icon />
Inside code you can directly require image using.
const src = require("../../assets/images/xyz.png");
Or
In order to dynamically load image need this.
const image = new window.Image();
image.src = require("../../assets/images/xyz.png");
image.onload = () => {
// do something if needed
};

createApp({}).mount('#app') clears #app's child elements in vue3

So I'm trying to add Vue3 to an existing asp.net core project. What I'd like to happen is for my razor app to render as normal, then use custom vue components to give my frontend a more reactive feel. However, when I mount an empty vue app to my wrapper div (parent of all other body content), it seems to be deleting all innerHTML of that wrapper div, completely removing all server rendered body content.
In my _Layout.cshtml file, I'm wrapping all content in a div with id 'app'.
<body>
<div id='app'>
#RenderBody()
</div>
<script src="~/js/vue-app/dist/js/chunk-vendors.76316534.js"></script>
<script src="~/js/vue-app/dist/js/app.bf4c5ba9.js"></script>
</body>
in main.js
import { createApp } from 'vue'
const vueApp = createApp({}).mount('#app');
// component definitions below
With the app set up like this, when I run my .net project I see a blank white browser window instead of the razor compiled html that I expect. In Vue2, it was possible to do this:
const vueApp = new Vue({
el: '#app',
data: {
....
},
methods: {
....
}//, etc
});
Which would result in the app being rendered as normalthe vue app bound to #app, making vue available to the child content (model binding, vue click handling, etc).
I've tried playing around with the isHydrate optional parameter on mount(), but it causes no change in the result.
Am I missing something here? How do you slowly migrate an existing project to use vue3 if you can't mount the app without clearing content? Any guidance is much appreciated.
Thank you
Notes:
vue-next runtime-dom source If this method is the mount method getting called, I'm not sure why container.innerHTML would not be getting set in the component. {} is not a function, and render/template is not defined for it.
vue-next runtime-core apiCreateApp source If this is the method getting called....I have no idea.
Update
Vue 3, without template renderer, will not be able to handle the templates after it has been compiled. To fix that, you can import vue/dist/vue.esm-browser (and vue.runtime.esm-browser.prod for prod), instead of the default vue. This will allow run-time component rendering.

Vue.js - Embed Swagger UI inside a Vue component?

I have a form in my Vue component which uploads the api file. Now I want to render the contents of the file like this:
I have imported swagger client library: https://github.com/swagger-api/swagger-ui.
Now, here
is an example of how you do it in a static page. But I need to do it inside a Vue component (or Quasar, specifically), so I do it like that:
Register swagger-ui inside my register components file:
<link rel="stylesheet" type="text/css" href="swagger-ui.css">
Now it is available as:
this.swaggerUI({})
anywhere in my components. Inside my component I have a div in a template to render the api file:
<template>
<q-form>here lies q-file element, submit button and other stuff</q-form>
<div id="swagger-ui"></div>
</template>
In the mentioned question he had something like:
<script>
window.onload = function() {
const ui = SwaggerUIBundle({
url: "https://yourserver.com/path/to/swagger.json",
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
]
})
window.ui = ui
}
</script>
Here's the difference: first of all, no window.onload, I must render it on submit button. Then, I deal with an uploaded file stored in my model, so no URL here. Now, I don't get how to make it work with locally stored file, when I try with the remote url, it gives me:
vue.esm.js?a026:628 [Vue warn]: Error in v-on handler: "Invariant Violation: _registerComponent(...): Target container is not a DOM element."
I was getting a similar error (Target container is not a DOM element) trying to use a static swagger spec. Instead of using window.onload, I found that Vue has the mounted() function, so this Vue 3 file worked for me:
<template>
<div class="swagger" id="swagger"></div>
</template>
<script>
import SwaggerUI from 'swagger-ui';
import 'swagger-ui/dist/swagger-ui.css';
export default {
name: "Swagger",
mounted() {
const spec = require('../path/to/my/spec.json');
SwaggerUI({
spec: spec,
dom_id: '#swagger'
})
}
}
</script>
This one appeared to be a simple yet very unobvious typo: in windows.onload function:
dom_id: '#swagger-ui',
must instead be
dom_id: 'swagger-ui',
without hash sign, that's it!

Aurelia Custom elments not showing

I'm working on an older Aurelia 1 project which earlier today started to give issues. After fiddling and reinstalling node_modules the thing runs but seems not to be loading any components. This is wat my structure looks like:
- elements
- form-login
- form-login.html
- form-login.js
- form-login.scss
- views
- authentication
- login.html
- login.js
- login.scss
(There's more but i'll leave that out for now.)
The login.html loads <form-login> like this:
<template>
<require from="elements/form-login/form-login"></require>
<main class="${ navigationInstruction.name }">
<form-login class="login__form" success.bind="CALLBACK_SUCCESS"></form-login>
</main>
The result is a blank screen, no contents of the <form-login> are ever rendered.
I've already found that he require tag should NOT point to the HTML file but to the directory/name of the component but this the case.
The contents of the form-login.js look like this (w/o irrelevant parts):
import {bindable, decorators} from 'aurelia-framework';
import './form-login.scss';
/**
* The application top navigation bar
*/
export const FormLogin = decorators(
bindable('success')
).on(class {
// Lots of code in here but constructor() is never fired.
});
Judging by the solution in comments it is an npm issue with package.lock.json file.
delete it along with node_modules and reinstall packages.