Is it possible to use vue-specific directives in localized text? - internationalization

I just started using vue-i18n and tried to use the v-on-directive (shorthand: #) in my language specific text.
What i tried to do:
// locale definition
let locale = {
en: {
withEventListener: 'Some HTML with <a #click="onClickHandler">event handling</a>'
}
}
and the vue template:
<!-- vue template be like -->
<p v-html="$t('withEventListener')" />
This doesn't throw an error but unfortunately it does not get evaluated by vue-js either. This would result to Plain-HTML like:
<p>
Some HTML with <a #click="onClickHandler">event handling</a>
</p>
So my question is if there is a way to make Vue 'evaluate' the text and thus 'translate' the directives within the text.

You can use Vue.compile to do something like this if you are including the standalone build script. I'm not familiar with vue-i18n, but this might put you on the right path.
Note that I had withEventListener to wrap it in a div because of the rules around templates.
let locale = {
en: {
withEventListener: '<div>Some HTML with <a #click="onClickHandler">event handling</a></div>'
}
}
const res = Vue.compile(Vue.t("withEventListener"));
Vue.component("internationalized", {
methods:{
onClickHandler(){
alert("clicked")
}
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
new Vue({
el:"#app"
})
With the template
<div id="app">
<internationalized></internationalized>
</div>
Working example.

Related

Passing and binding img src from props in Vue.js

I am trying to display an image with the img tag by using a path from props for the src attribute.
I've tried changing the path with #, using the whole path with src, adding ../assets/ in the component and only passing the file name (orange.png) as props.
I always get the default broken image displayed.
When inspecting in the browser, the path seems fine.
When I display the image directly, I can see that the path is resolved to some different path <img data-v-1212d7a4="" src="/img/orange.7b71a54c.png">.
Edit:
Additionally I tried this post Can't dynamically pass relative src path for imgs in Vue.js + webpack ,
where using <img :src="require(picture_src)" /> is given as an answer.
This leads to an error: Error in render: "Error: Cannot find module '../assets/orange.png'"
(Edit2:
This answer in the end worked for me in the end as described in my answer post.)
The same error occurs with the similar webpack method using let images = require.context('../assets/', false, /\.png$/) in my script part, as the answer on this post Can't dynamically pass relative src path for imgs in Vue.js + webpack .
I am new to Vue.js, so I don't exactly know what is happening or how to search for this or it might not have anything to do with what I'm originally trying.
I am able to display my image when I pass the path directly, like this
<img src="../assets/orange.png"/>
Now I'd actually like to pass it to my component in the props and then, inside the component, display it reading the path from props.
Component
<template>
<div>
<img :src=picture_src />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
}
}
</script>
Using the component:
<template>
<div>
<PictureCard pic_desc='some description text' picture_src='../assets/orange.png' />
</div>
</template>
<script>
import PictureCard from './components/PictureCard.vue'
export default {
name: 'app',
components: {
PictureCard
}
}
</script>
If it is possible, I'd love to display my from a path that is passed through the component's props.
Otherwise I'd love to know some other solutions, work-arounds or knowledge on best practices in this case.
This worked for me
<img :src="require(`#/assets/img/${filename}`)">
where filename is passed in as a String prop e.g. "myImage.png".
Make sure you use the path specific to your project.
Source: https://github.com/vuejs-templates/webpack/issues/450
Note: # is a webpack alias for /src that is set by default in Vue projects
After some research, I understand that my problem has to do with webpack and resolving filepaths. I used a modified version from this answer:
Vue.js dynamic images not working
and this answer:
Can't dynamically pass relative src path for imgs in Vue.js + webpack
Since the link in the second answer was dead, here's an active link to require.context documentation:
https://webpack.js.org/guides/dependency-management/#requirecontext
My mistake when trying the second link's answer was that I returned only orange.png as the path, while I needed to add ./ at the beginning.
My working picture component now looks like this.
<template>
<div>
<img :src="resolve_img_url(picture_src)" />
<div class="pic_sub">{{pic_desc}}</div>
</div>
</template>
<script>
export default {
name: 'PictureCard',
props: {
picture_src: String,
pic_desc: String
},
methods: {
resolve_img_url: function (path) {
let images = require.context('../assets/', false, /\.png$|\.jpg$/)
return images("./"+path)
}
}
}
</script>
I edited the regular expression to match .png and .jpg file endings. Therefore passing the prop looks like this now
<PictureCard picture_src='orange.png' pic_desc='some picture description'/>
This works for me:
This is how i use my Componenent.
<image-element
:imageSource="require('#/assets/images/logo.svg')">
</image-element>
My Image Component:
<template>
<div>
...
<img v-bind:src=imageSource />
...
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'nuxt-property-decorator'
#Component({
components: {
.....
}
})
export default class extends Vue {
...
#Prop({ default: '' }) imageSource!: String
...
}
</script>
Newer solution:
The 'require()'-method does not work when using Vite.
I got this error: ReferenceError: require is not defined.
This is how I solved it without 'require()' and with composition API:
From parent component:
<ChildComponent icon-filename="icon.svg" />
ChildComponent:
<template>
<div>
<img :src="getImageUrl()">
</div>
</template>
<script setup lang="ts">
import {defineProps} from "vue";
const props = defineProps({
iconFilename: String
})
function getImageUrl() {
// This path must be correct for your file
return new URL(`../assets/icons/${props.iconFilename}`, import.meta.url)
}
</script>
this is my favorite super simple way to do it. It can easily be reused in any file in any folder in my project. Just pass the actual path as a string from the perspective of the parent:
//some file
<ParentA>
<ImageComponent
myImagePath="../../../../../myCat.png"
/>
</ParentA>
//some other file in a different folder in my project
<ParentB>
<ImageComponent
myImagePath="../../myCat.png"
/>
</ParentB>
//child component file
<template functional>
<div>
<img :src="props.myImagePath">
</div>
</template
Thats all not working for me :D
The template File is wrong!
you need to add ":" before you set your prop.
thats how i should use the PictureCard
<PictureCard :picture_src="require('orange.png')"
pic_desc='some picture description'/>
and thats how my PictureCard should look like:
<template>
<div>
<img v-bind:src="picture_src" />
</div>
</template>
export default class PictureCard extends Vue {
#Prop({ default: require("#/assets/orange.svg") }) img!: string
}
so in case no prop is setted, so i added a default prop too.
and yes i only used the image.

Why isn't the Vue custom and non-custom prop validators working on this?

I have two Vue components here and everything is writing out fine to the page. The only issue is the props validator. It doesn't seem to be looking at the arrays and filtering out the ones that have numbers in them and that aren't equal to four items. It's just printing out everything to the page. What is wrong with this code? Thanks for any help that can be given!
I've looked up Vue documentation and YouTube videos but it seems like I've already done what is suggested. I'm following what they have so it seems I'm missing something no how the value gets passed to the prop? Not sure.
Here's the HTML:
<div id="app">
<course :menu="menu1"></course>
<course :menu="menu2"></course>
</div>
Here's the VUE code I have:
Vue.component("dish",{
template: `
<p>{{food}} < - Delicious!</p>
`,
props:["food"]
})
Vue.component("course",{
template: `
<section class="course">
<dish v-for="f in menu" :food="f"></dish>
</section>
`,
props: {
menu:{
type:String,
required:true,
validator(foodArray){
return foodArray.every(food=>typeof food === "string") && foodArray.length === 4
//PROBLEM SEEMS TO BE RIGHT HERE ABOVE THIS ISN'T VALIDATING
}
}
}
})
new Vue({
el:"#app",
data:{
menu1:["apple","pear","lemon",22],
menu2:["hamburger", "fries", "shake", "soda","poop"]
}
})

Getting value from inside div using XPATH

I have the following div
<div data-dmid="product-detail-page" itemscope="" itemtype="http://schema.org/Product" itemid="3600542198158">
from which I would like to extract the itemid -> 3600542198158
I was using the following Xpath which does however not return any value:
//div[#data-dmid='product-detail-page']/#itemid
Could please someone advise how to built the Xpath correctly for it
#
Unfortunately I have to renew my question.
I was looking for the code with Firefox inspection tool.
Looking at the html source code which is different to the output with the inspection tool I have the following part which will be interesting:
<div class="onCanvas content-with-footer">
<div id="container-main" class="content-main">
<div data-dmid="uvp-banner-container" style="height: 54px; width: 100%"></div>
<script>
document.addEventListener("DOMContentLoaded", function() {
var props = {};
ReactInit.initReactComponent("contentViewService", "UvpBannerContainer", props, document.querySelector("[data-dmid='uvp-banner-container']"));
});
</script>
<div id="react-product-detail-page"></div>
<script>
var props = {
gtin: 3600542198158,
locale: dmSettings.localeLanguage
};
ReactInit.initReactComponent("product-detail-page", "ProductDetailPage", props, document.getElementById("react-product-detail-page"));
$(document).ready(function () {
var props = {
locale: dmSettings.localeLanguage
};
ReactInit.initReactComponent("product-detail-page", "PriceLegend", props, document.getElementById("react-price-legend"));
});
</script>
I would need to get the gtin (plain number) of the second script.
I would like to use the xpath in a scraping tool why only plain xpath code will work for me.
Thank you again and please excuse my previous not fully correct question.
I am assuming that you don't mind JavaScript and jQuery since you didn't specify:
var itemId = $("div[data-dmid]").attr("itemid");
console.log(itemId);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-dmid="product-detail-page" itemscope="" itemtype="http://schema.org/Product" itemid="3600542198158">
I got the answer with help of another post on Stackoverflow.
Reading a javascript variable's value
The correct code for my updated question is
substring-before(substring-after(//div[#class='onCanvas content-with-footer']//script[2][contains(.,'gtin')]/text(), "gtin: "), ",")
Thank you for any help.

Comment out a part of Vue template element

Sometimes it is needed to comment out some element attribute without having to remember it in order to restore it quickly after some tests.
Commenting out whole element is achievable with HTML commenting syntax
<div>
<!-- <h2>Hello</h2> -->
<span>hi</span>
</div>
However this won't work with a single attribute (causes rendering error)
<my-comp id="my_comp_1"
v-model="value"
<!-- :disabled="!isValid" -->
#click="handleClick">
</my-comp>
The best approach I could see and used before was to make a tag backup by copying whole element and settings v-if="false" for it (or comment out whole copied element) and continue to experiment with original one
I don't think you can put an HTML comment inside a component tag, for much the same reason you can't put comments inside an HTML element opening tag. It's not valid markup in either situation. I think the closest you could come would be to place the comment in the quotes:
:disabled="// !isValid"
Which would have the same effect as:
:disabled=""
Depending on whether your component can handle that value being missing, that might fit your needs.
Prefix the attribute value with data- or Wrap with data attribute.
<my-comp id="my_comp_1"
v-model="value"
data-:disabled="!isValid"
data-_click="handleClick"> # `#` could not be used
</my-comp>
or
<my-comp id="my_comp_1"
v-model="value"
data='
:disabled="!isValid"
#click="handleClick">
'>
</my-comp>
I'll with the attribute set to something like data-FIXME.
I got these solutions to work. I thought of solution 1.
Starting code:
<div
v-for="foo in foos"
:key="foo.id"
#click="foo.on = !foo.on /* JavaScript comment. */"
>
<label>
{{ foo.name }} {{foo.on}}
</label>
</div>
The Vue directive HTML attribute that needs to be disabled: #click="foo.on = !foo.on"
How the final div tag will run:
<div
v-for="foo in foos"
:key="foo.id"
>
Solutions 1 and 2 keep the disabled attribute inside its tag. I didn't find a good way to make a "raw string". To keep the attribute in the tag, the outer and inner quotes must be different.
sol. 1: I made a new v-bind attribute (:lang) to put the disabled attribute in.
:lang='en /* #click="foo.on = !foo.on" */'
Sol. 2: Pick a Vue directive. Put the attribute in.
v-for="foo in foos /* #click='foo.on = !foo.on' */"
Solutions 3 and 4 put the attribute outside the tag.
Sol. 3:
<div v-if="false">
#click="foo.on = !foo.on"
</div>
Sol. 4: <!-- #click="foo.on = !foo.on" -->
One way to remove/hide component attributes is to create a custom directive for it.
Let's say you create a directive called v-hide and put it in your component as:
<my-comp v-model="value" #click="handleClick" v-hide :disable='true'></my-comp>
And the output would be:
<my-comp v-model="value" #click="handleClick"></my-comp>
Here is a working example:
Vue.component ('my-component', {
template: `<p> A custom template </p>`
})
Vue.directive('hide', {
inserted: function (el) {
console.log('el before hide', el)
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
console.log('el after hide', el)
}
})
new Vue({
el: '#app',
data () {
return {
someValue: 'Hello'
}
}
})
<script src="https://unpkg.com/vue#2.5.3/dist/vue.js"></script>
<div id="app">
<my-component v-model='someValue' v-hide :disable='true'></my-component>
</div>

use parse react query results as an html tag attribute

This is my first time asking a question so I am a true SO newbie. I am currently working on a mobile app and I am using Parse React and Ratchet to build it. I have read the React documentations on FB github and apparently do not understand all enough to solve some problems. One of my problems is using the results of a Parse Query in the observe function of the declared ParseComponent as a value of a rendered react component, which in turn attempts to render the passed value as HTML. Below is the parent object:
export default class CategoryPage extends ParseComponent
{
observe(props,state){
return{
category: new Parse.Query('BusinessCategory').equalTo("objectId", this.props.categoryId)
};
}
render() {
return (
<div>
<Header text={this.data.category.objectId} back="true"/>
<div className="content">
<BusinessList categoryId={this.data.category.objectId}/>
</div>
<NavBar />
</div>
);
}
};
Notice I am passing the objectId of the category found in the Query as a text attribute of the Header React component. I am expecting Header as a child to use the passed property as follows:
var Header = React.createClass({
render: function () {
return(
<header className="bar bar-nav">
<h1 className="title">{this.props.text}</h1>
</header>
);
}
});
However the h1 is not rendering anything! I am thinking that this.data.category.objectId is a string and therefore should be rendered in the h1 tag as a string.
I do appreciate your answers very much.

Resources