attribute binding in vue 3 - vue.js

I'm new to Vue and currently trying to dynamically change the video or image source link by passing the data in through a prop. I created a component with specific template structure that I would like to pass in the source from the main app.js page. I've tried binding it in both areas but unsure if I'm doing it correctly. I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly.
parent element contains 'Video' component-
<Video theme="IL" :vidSrc="srcIL.vid"></Video>
import Video from "./components/Video.vue";
export default {
name: "App",
components: {
Video
},
data() {
return {
srcIL: {
vid: "./assets/invi-lines/invisible-lines-film.mp4"
}
};
}
child 'Video component'
<template>
<div class="introVid top">
<video controls :src="vidSrc"></video>
</div>
</template>
<script>
export default {
props: ["theme", "vidSrc"]
};
</script>

This seems like you have it set up properly, and it is hard to know exactly what is causing the issues from the info provided, but I'm going to make a guess that it might be that the asset is not getting bundled.
I tried using regular divs and stuff to embed the video in app.js and it shows the content perfectly
I suspect you had something like:
<video controls src="./assets/invi-lines/invisible-lines-film.mp4"></video>
which would have taken the resource from the assets and packaged it for use.
see relative-path-imports for details.
You can try forcing these to load using require somewhere in the project, which will force the compiler to copy the asset, but really, if you have dynamic assets (assuming there's more than a handful and they can change) you should have them in the public folder already, not in the source folder. So my recommendation is that you move the dynamic assets to the public folder (assuming that was your issue to begin with)

Related

Nuxt not automatically importing components from nested directory

In my nuxt app, components in nested directories are not automatically importing as expected. For some of my components i have something like the following:
vue 2.6.12, nuxt 2.15.0
components\ Directory structure
TopArea\
--SomeComponent.vue
<template>
<header class="header">
<div>Hello</div>
<SomeComponent />
</header>
</template>
No other component in the application has the name SomeComponent. In the example above i get the error: Unknown custom element: <SomeComponent> - did you register the component correctly? For recursive components, make sure to provide the "name" option.. I can get around the issue by specifying the directory name before the component filename (TopAreaSomeComponent), use the prefix option in nuxt.config, or by manually importing the component. This is confusing because the docs state:
Nested Directories
If you have components in nested directories such as:
components/baseButton.vue
The component name will be based on its own filename. Therefore, the component will be:
<button />
It goes on to say "We recommend you use the directory name in the filename for clarity". But that seems like a rule than a recommendation. If i don't use the directory name as part of the filename, dynamic imports are not working for components in nested directories.
Is this an error in the docs or am I reading it wrong?
Since Nuxt 2.15.0, components changed in the way they work as stated in this github issue.
Depending of you structure and how you want to handle your organization, you may edit your configuration accordingly to the migration guide available here: https://github.com/nuxt/components#v1-to-v2
Or you could also simply set the pathPrefix option to have all your components available without any prefix at all.
nuxt.config.js/ts
components: [
{
path: '~/components', // will get any components nested in let's say /components/test too
pathPrefix: false,
},
]
PS: this solution also works with Nuxt3.
This documentation actually do need an update, indeed: https://nuxtjs.org/docs/2.x/directory-structure/components#components-discovery
This is how it works: for a given page
<template>
<div>
<yolo-swag /> <!-- no need for <nested-yolo-swag /> here -->
</div>
</template>
And with the following file tree
Update for Nuxt3
Looks like this is the new official syntax
import { defineNuxtConfig } from 'nuxt'
export default defineNuxtConfig({
components: {
global: true,
dirs: ['~/components']
},
})
This may answered already. But to illustrate the solution to comers here here's the way according to docs:
<TopAreaSomeComponent />
if your components is nested deeply:
components / TopArea / SomeComponent.vue
https://nuxtjs.org/docs/directory-structure/components/#nested-directories

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 Template - Making any URLs found in returned text string to a link

I am working on a project that is Vue modular based (code used is: https://github.com/mishushakov/dialogflow-web-v2/blob/bc3ce7d7cf8e09a34b5fda431590bd48cc31f66b/src/App.vue)
Linking to the file I think need to make the change to, have been trying but I don't really know Vue at all and had not luck.
The returned message is plain text for example: this is a test message, please visit https://wwww.google.com
What I am trying to do, is from that text string, if a URL found is to create a link from that found URL
<RichComponent><RichBubble v-if="message.queryResult.fulfillmentText" :text="message.queryResult.fulfillmentText" /></RichComponent>
Is what the current code is that returns the data.
Is there a best way to achieve this? Is there a core function maybe?
I have tried to npm install linkify but cannot seem to get it working so maybe a direct approach would be better?
You can use linkifyjs to convert links in a string into anchor tags. The linkifyjs/lib/linkify-string.js file augments the String prototype with a linkify() method.
<template>
<p v-html="msg.linkify()"></p>
</template>
<script>
import 'linkifyjs/lib/linkify-string' // side effect: creates String.prototype.linkify
export default {
props: ['msg'],
}
</script>
It also exports that method if you prefer an explicit call:
<template>
<p v-html="linkify(msg)"></p>
</template>
<script>
import linkify from 'linkifyjs/lib/linkify-string'
export default {
props: ['msg'],
methods: {
linkify,
}
}
</script>

Creating a path to an asset dynamically

The issue is how to get Vue to render the correct path for an asset, if the path to the asset and the assets name is passed through as a props.
Explanation:
When using a Vue component... if passing in props which contain a path and a file name of an asset to be loaded
export default{
name: 'NewComponent',
props: ["path","file"],
computed:{
calculateCompletePath (){
return this.path+""+this.file;
}
}
}
If using something like the above in a manner such as:
<template>
<div>
<video>
<source :src="calculateCompletePath" type="video/mp4"/>
</video>
</div>
</template>
How can you get the src portion to render correctly - e.g Vue generates its own string referencing the media folder for example
/media/movie.6ac43bcf.mp4
Side note:
I've read somewhere there is the possibility to using require (<<asset>>) but that doesn't seem to work if used on the computed function e.g. return require (this.path+""+this.file);
Any ideas how to get this to work?
Please refer this document for a detailed explanation on how to resolve static assets:
https://cli.vuejs.org/guide/html-and-static-assets.html#relative-path-imports
I think the problem is that your asset(in this case an mp4 file) is not located in your computer's /media folder.
See these 3 points for a better understanding: https://cli.vuejs.org/guide/html-and-static-assets.html#url-transform-rules
If your media folder is located under the root folder(/), then, the computed value /media/movie.6ac43bcf.mp4 will work.
If your media folder is under src folder of the app, your computed property should return #/media/movie.6ac43bcf.mp4
If your media folder is somewhere else, then you should create a proper path using #/ or the ./ symbol to reach the file correctly.

How to mix Vue components with HTML outside the template

Think about a wordpress blog, or a standard CMS with some content. I use a wysiwyg editor (CKEditor) to write my contents and save them to db.
I want to use some Vue components inside this HTML, and so I add a wrapper div to my theme. HTML pages are wrapped by
<div id="#my-custom-app">
...html from server
</div>
Basically I want to add for example
<my-app-image-compare></my-app-image-compare>
using CKEditor inside my HTML, then I will create an app mounted on #my-custom-app div. I will insert the app at the end of the html body.
Vue.app file doesn't have a template, the template is basically my HTML page written with CKEditor, but every component is loaded and defined by the app and every component has a template.
How can I do? Is there a way to have a main Vue app file without a defined template?
Option 1:
First create a vue container on a basic template. This template will then load a component which gets your data from the sever and displays it, so:
// This is your main vue instance container
<div id="#my-custom-app">
<dynamic-html v-if="myHtmlFromServer" template="myHtmlFromServer"></dynamic-html>
</div>
Within this main component, you need to hook up created event and populate myHtmlFromServer with your HTML content from the editor.
import DynamicHtml from './myComponents/DynamicHtml'
new Vue({
el: '#my-custom-app',
data () {
return {
myHtmlFromServer: ''
}
},
components: {
DynamicHtml
}
created () {
// this.myHtmlFromServer = this.getDataFromServer()
}
})
The <dynamic-html> component, would have props: ['template'] and on the created event would assign this.$options.template = this.template.
This option will set the HTML template of that component and allow Vue to render it as normal (meaning you can then do {{someVal}} in your CKEditor.
Option 2:
Another option is if you're using a server side language like PHP, then you could just put that html on the page i.e echo $myHtmlContent and as long as that content contains <div id="#my-custom-app"> you Vue instance will mount. PHP will add the HTML to the page before the JS processes the page so it'll just work.