How can I get vue-loader to interpolate asset urls? - vue.js

I have an image with a dynamic (interpolated) src attribute.
<img src="./{{bar}}.jpg"/>
How do I get vue-loader to interpolate {{bar}}?

I'm pretty sure that your code throws a warning (not referred it):
[Vue warn]: src="./{{bar}}.jpg": interpolation in "src" attribute will cause a 404 request. Use v-bind:src instead.
So, you should bind the value:
<img :src="'/assets/' + bar + '.jpg'">
The above example it loads an image xxx.jpg from the static directory assets, but not via loader yet.
To accomplish that, you should use a dynamic require:
<img :src="loadImage(name)">
methods: {
loadImage (imgName) {
return require('./assets/' + imgName + '.jpg')
}
}
NOTE
It is not recommended if the directory contains a large number of files, because the webpack will be load all the files which match your request (for the above example: ./assets/*.jpg).

In attribute interpolation is not allowed, use v-bind instead
https://v2.vuejs.org/v2/guide/syntax.html#Attributes

Related

How to build Vue dynamic assets (image) path?

I have a list with several elements (id, name, img_name ). In my asset folder I have a subfolder svgs (srs/assets/svgs). There are the SVGs (logo1.svg, logo2.svg). If I hard code the link it works very well: <img src="#/assets/svgs/brand1.svg" alt="">.
But when I build it dynamically (with a method) it doesn't work. I get a 404. The reason is that it does not interpret #/assets/. He thing it is a string and a part of the path. What i have to change that it works?
<template>
...
// inside a loop
<img :src="makeImgPath(item.img_name)" alt="">
...
</template>
...
methods() {
makeImgPath(imgName) {
return "#/assets/svgs/" + imgName + "svg";
}
}
...
Network says: 404 newapp/#/assets/svgs/brand1.svg
As you have correctly pointed out, vue does not interpret #/asstes. # also only stands for src/. For this reason, you can replace the # with src, then it should work.
makeImgPath(imgName = 'defaultImageName') { // suggestion
return "src/assets/svgs/" + imgName + "svg";
}

Cant load content – TypeError: Cannot read properties of null (reading 'attributes‘)

currently working on an issue and cant figure out why my page throws me an error.
Having this component:
<JobDetailSectionText
:variant="tmpl({ red: 1, blue: 4, yellow: 7 })"
:image-src="
jobProfile.attributes.imagePractice
? $strapi.options.url +
jobProfile.attributes.imagePractice.data.attributes.url
: '/static/img/praxisteil.jpg'
"
:image-alt="
jobProfile.attributes.imagePractice.data.attributes.alternativeText
"
>
In my content manager in Strapi I changed the „attribute.imagePractice" from required = true to false and now want to, if no file is added to the database show a default image in '/static/img/praxis.jpg‘.
But the console of the page gives me an error
"TypeError: Cannot read properties of null (reading 'attributes')
I tried to figure out the source of the problem but the page only works if I add and imagePractice in the backend, it won’t take the default img I tried to declare with the static path.
Any thoughts?
Thanks!
You can use optional chaining to check if property is exist
<JobDetailSectionText
...
jobProfile.attributes?.imagePractice
? $strapi.options.url +
jobProfile.attributes.imagePractice.data.attributes.url
: '/static/img/praxisteil.jpg'
"
...
>
#DinhTX solution is good, but note, that you cannot use optional chaining unless it's Vue 3. Read more here.
If you're using Vue version less then 3 you would need to write a computed property for that src attribute value where you'd check if attributes exist. Actually, I'd recommend you to use computed property anyway cause Vue's templates should be more HTML and less JS (not like React).
Example of computed property would be:
computed: {
jobSrc() {
const strapiUrl = `${$strapi.options.url}${jobProfile.attributes.imagePractice.data.attributes.url}`
return jobProfile.attributes?.imagePractice ? strapiUrl :'/static/img/praxisteil.jpg'
}
}

How to import a directory into a single file component

I am using a photo gallery component in my project. It requires a path to the folder containing the images. I am unable to find a way to do this. I have created an img directory inside of assets, and I'm using the standard Vue CLI 3 scaffolding. I'm able to use a require('path/to/file/name.png'), but what I need is to be able to bring the whole folder in. I'm unable to figure out a way to do this. I even tried placing the images in a folder inside of public, but no luck.
My structure looks like this:
project/public/img
project/src/assets/img/
project/src/components/
I need to get the project/src/assets/img path into a component inside of project/src/components/componentName.vue.
I should also mention that I want to be able to access this directory from the script tag, not the template tag.
You can try something like this:
const requireModule = require.context('../assets/img.',false,/\.png$/)
const images = {}
requireModule.keys().forEach(filename =>
{
const imageName = fileName.replace(/(\.\/|\.png)/g, '');
images[imageName] = requireModule(fileName)
OR
images[imageName] =
{
namespaced: true,
...requireModule(fileName)
}
});
export default images;
Then you can import this file
import photos from 'imagesObject.js'
for (let key in photos) // do whatever you want with the image
Thank you for your answer IVO. That solution did work, but I found another that I wanted to share here for anyone else having a similar problem. The issue I was having was incorrectly referencing the public folder using a relative path instead of BASE_URL. Based on this...
The public Folder Vue CLI Documentation
I created a directory inside of /public then referenced it using process.env.BASE_URL. This solved the problem. Here are the relevant snippets:
Javascript:
data () {
return {
thumbnailDir : process.env.BASE_URL + 'portfolio/'
}
Template:
<transition-group name="thumbnailfade" tag="div">
<img v-for="thumb in filteredImages"
:key="thumb.id"
#click="showLightbox(thumb.name)"
:src="thumbnailDir + thumb.name"
:alt="thumb.alt"
:title="thumb.alt"/>
</transition-group>
<lightbox id="mylightbox"
ref="lightbox"
:images="images"
:directory="thumbnailDir"
:filter="galleryFilter"
:timeoutDuration="5000"
/>

Riotjs - Front-end page Structure

I'm using the riot for the system. but I have a problem using the common tag in every place. because I have to copy the all common tag each page.
I added all tags like this. Does anyone have the solution for this ?
<st-service>
<st-alert></st-alert>
<st-header></st-header>
<st-body></st-body>
<st-footer></st-footer>
</st-service>
<st-profile>
<st-alert></st-alert>
<st-header></st-header>
<st-body></st-body>
<st-footer></st-footer>
</st-profile>
I found a solution, I'm using this method to handle these common tags. like this
<st-common>
<st-alert></st-alert>
<st-header></st-header>
<yeild></yeild>
<st-footer></st-footer>
</st-common>
service-page.tag // page
<st-service-page>
<st-common>
<st-service></st-service>
</st-common>
<st-service-page>
profile-page.tag // page
<st-profile-page>
<st-common>
<st-profile></st-profile>
</st-common>
<st-profile-page>
service-view.tag
<st-service>
// html / code body related to module
</st-service>
profile-view.tag
<st-profile>
// html / code body related to module
</st-profile>
If needed in details about this I can explain.
I'd have to know more about how you're routing to say for sure, but I think you should avoid using a different outer tag for each page. If your HTML looks something like this:
<body>
<st-app />
<script>
const pages = {
"/": "st-home",
"/about/": "st-about",
}
const content_tag = pages[window.location.pathname] || "st-notfound"
riot.mount("st-app", {
content_tag: content_tag
})
</script>
</body>
Then <st-app> would be defined something like:
<st-app>
<st-alert></st-alert>
<st-header></st-header>
<div data-is={this.opts.content_page}></div>
<st-footer></st-footer>
</st-app>
The important thing here being that you're controlling which tag should be used via the data-is attribute and the mounting options for <st-app>. In this example <st-home>, <st-about>, and <st-notfound> are riot components defined elsewhere.

using dijit.byId w dojox.mobile widgets

I'm dynamically building a series of dojox.mobile.ListItem widgets under a statically defined dojox.mobile.RoundRectList widget via this function...
function displayOpps(items) {
// Create the list container that will hold application names
var rrlOppsContainer = dijit.byId("rrlOpps");
// Add a new item to the list container for each element in the server respond
for (var i in items){
// Create and populate the list container with applications' names
var name = items[i].CustName + " - " + items[i].OppNbr;
var liOpps = new dojox.mobile.ListItem({
label: name,
moveTo: "sv3OppDetail"
});
// Add the newly created item to the list container
rrlOppsContainer.addChild(liOpps);
}
}
When I run this code during onLoad() in my html file, I get the following error using Chrome's dev tools...
Uncaught TypeError: Object # has no method 'byId'
I've read numerous articles around this topic and it appears that lots of folks have this problem, but each that I have found are in relation to some other technology (e.g., Spring MVC, etc) and I'm attempting to use it w a dojox.mobile based app. That said, I attempted to mimic some of the solutions brought up by others by including this in my html file, and it still doesn't work...
<script type="text/javascript"
data-dojo-config="isDebug: true, async: true, parseOnLoad: true"
src="dojo/dojo.js">
dojo.require("dojox.mobile.RoundRectList")
</script>
What am I doing wrong?
Thank you in advance for your time and expertise.
If you are using Dojo 1.7+, you probably just forgot to require the "dijit/registry" module. This where the byId function is defined. When you use desktop widgets, this is loaded indirectly by other base modules, but with dojox/mobile you must load it explicitly (because dojox/mobile loads only a very minimal set of modules by default, to minimize code footprint).
Depending on how you wrote your application, do this:
dojo.require("dijit.registry"); // legacy (pre-1.7) loader syntax
...
var rrlOppsContainer = dijit.byId("rrlOpps");
...
or this:
require(["dijit/registry", ...], function(registry, ...){ // 1.7+ AMD loader syntax
...
var rrlOppsContainer = registry.byId("rrlOpps");
...
});
Note also that your second code sample tries to use asynchronous loading (async: true) while it uses the legacy loader syntax. This won't work, to get async loading you must use the AMD syntax.