Add custom character after i18 translation Vue - vue.js

So, I'm having an issue adding custom characters after a translated word using i18n. To be more precise, this is the case :
<v-text-field
v-bind:placeholder="$t('wordCapitalTitle')"
/>
In the above form, the translation works perfectly, I get the 'Title' placeholder value, which is correct.
But what I'm trying to do, is to be able to add extra characters, that doesn't affect the initial translation.
For example, instead of 'Title', I want the placeholder value to be 'Title*', but I cannot find a way to properly add the '*'.
I tried escaping the character using the unicode value, but if I do that, instead of 'Title*', I get 'wordCapitalTitle*'.
Can anyone give me a hint what should I do in order to make this possbile? Thanks alot!

Just use the string template syntax with backticks :
<v-text-field
v-bind:placeholder="`${$t('wordCapitalTitle')}*`"
/>

You can use template literals to concatenate the *
Demo :
Vue.locale('en', {
foo: {
bar: 'English'
}
})
Vue.locale('el', {
foo: {
bar: 'Ελληνικά'
}
})
new Vue({
el: '#demo',
methods: {
change () {
let current = this.$lang.lang
if (current === 'en') {
this.$lang.lang = 'el'
} else {
this.$lang.lang = 'en'
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-i18n/4.6.0/vue-i18n.min.js"></script>
<div id="demo">
<input type="text" v-bind:placeholder="`${$t('foo.bar')}*`"/>
<button #click="change">change</button>
</div>

Related

How to use vuetify's v-img inside v-html

I would like to use <v-img> of vuetify inside v-html to replace the standard <img>, i.e.
<div v-html="'<v-img src="some_image_url" />'">
I understand that v-html is meant for only standard HTML component, and I would like to know if there is anyway to use a custom component (such as <v-img>) inside v-html.
The example below uses some cheap and cheerful RegExps to do the parsing, nothing I would use in production code. My focus was on how to avoid using v-html rather than finding a reliable way to parse out the <img> tags.
The key thing I'm trying to demonstrate is how you can parse the text into chunks and then iterate over the chunks in the template to create v-img components. I've used a dummy component for v-img but the principle would be exactly the same for the real thing.
new Vue({
el: '#app',
components: {
vImg: {
template: '<strong>[<slot/>]</strong>'
}
},
data () {
return {
text: 'Something something <img src="somepath"> and <img src="otherpath">'
}
},
computed: {
chunks () {
const re = /(<img\s[^>]*>)/g
const text = this.text
const parts = text.split(re).filter(part => part)
return parts.map(part => {
if (part.match(re)) {
const matchSrc = part.match(/\ssrc="([^"]*)"/)
return {
src: matchSrc && matchSrc[1]
}
}
return part
})
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<template v-for="chunk in chunks">
<template v-if="typeof chunk === 'string'">{{ chunk }}</template>
<v-img v-else>{{ chunk.src }}</v-img>
</template>
</div>
I managed to solve it with v-runtime-template, which can be found here:
https://github.com/alexjoverm/v-runtime-template
Cheers!

How to save an existing content?

I can't get how to use v-html to save an existing content. For example:
<div ref="content" v-html="content">Hello, World! A lot of divs</div>
How to make to div content was replace only when I will assign a some not null value with content? Or how to make it in another way? Or is the single way to request div content asynchronously?
The next way works, of course, but I lose a data binding.
this.$refs['content'].innerHTML = "New content";
P.S. I am migrating from jQuery and still can't think in Vue.js philosophy clearly.
Actualy, you must read vue documentation.
In your component you must declare content in data, and simply change it in oher places, i.e. in button's click handler or inside component's methods:
new Vue({
el: "#root",
data: function () {
return {
content: 'Hello, World! A <b>lot</b> of divs'
};
},
methods: {
changeText: function() {
this.content = 'This text from component';
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="root">
<div v-html="content"></div>
<button v-on:click="content = 'This text from button'">Click me</button>
<button v-on:click="changeText">And me</button>
</div>
You could assign a default value to content.
data () {
return {
content: 'Hello, World! A lot of divs'
}
}
When you'll assign a new value to content it will get rendered.
Another way would be to check if content is not null and have 2 different divs using v-if/v-else for conditional rendering.
<div v-if="content" v-html="content"></div>
<div v-else>Hello, World! A lot of divs</div>
and the script
export default {
name: 'customComponent',
data () {
return {
content: null
}
}
}

How can I get other root data in component under the v-for statement?

I also want to access add string in the template but it seems like not work.
please help me solve my problem here...
Vue.component('comp',{
template:`
<div id="test">
<div v-for="(item,index) in this.$root.items">
<p>{{this.$root.string}}</p>
<p>{{item}}</p>
</div>
</div>
`
})
var vm = new Vue({
el:'#test',
data:function(){
return {
'string':'xxx',
'items':['a','b','c']
}
}
})
http://jsfiddle.net/89kgnrvf/5/
change this.$root.items to $root.items
You don't have to prefix with this. when you're inside the template of your component.
So, you just have to replace this.$root.items by $root.items and this.$root.string by $root.string.
However, you need to prefix with this. if you're referencing the value inside your Vue object.
Example :
computed: {
exampleComputed: function () {
return this.string;
}
}
And the corrected JSFiddle : http://jsfiddle.net/89kgnrvf/19/

vuejs - computed is not working with props

I'm using props to update my site content in the child component. This is basically working like this:
<child-component :updatedArray="updatedArray" />
then in the child component:
<template>
{{updatedArray}}
<div>{{computedArray}}</div>
</template>
<script>
props: ['updatedArray'],
...
computed: {
computedArray() {
if(this.updatedArray.item == "item one") {return "item one"}
else {return "other item"}
}
}
</script>
Now this code should work in any case when I update updatedArray in my parent component. Then I see in my child component that my {{updatedArray}} is changing correctly, but my computedArray is not triggered and does not work.
Can I ask you why is this happening?
Does computed do not work with every props update?
How should I correct my code?
edit: not duplicate
I'm not mutating the prop, I rather only do a computed based on its value.
Your bind uses wrong name.
As Vue Guide describes:
HTML attribute names are case-insensitive, so browsers will interpret
any uppercase characters as lowercase. That means when you’re using
in-DOM templates, camelCased prop names need to use their kebab-cased
(hyphen-delimited) equivalents
So you need to convert camelCase to kebab-case.
like v-bind:updated-array instead of v-bind:updatedArray.
Below is one working demo using kebab-case. You can change it to camelCase, then you will find not working.
Vue.component('child', {
template: '<div><span style="background-color:green">{{ updatedArray }}</span><div style="background-color:red">{{computedArray}}</div></div>',
props: ['updatedArray'],
computed: {
computedArray() {
if(this.updatedArray.item.length > 0) {return this.updatedArray}
else {return "other item"}
}
}
})
new Vue({
el: '#app',
data() {
return {testArray: {
'item': 'test',
'prop1': 'a'
}}
},
methods:{
resetArray: function() {
this.testArray['item'] += this.testArray['prop1'] + 'b'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<button v-on:click="resetArray()">Click me</button>
<child v-bind:updated-array="testArray"></child>
</div>

Get reference to element in method in Vue.js

How can I get reference to the element that fired the method in Vue.js?
I have HTML like this:
<input type="text" v-model="dataField" v-bind:class="dataFieldClass" />
And in my Vue.js viewmodel I have a method:
dataFieldClass: function () {
// Here I need the element and get its ID
// Pseudo code
var elementId = $element.id;
}
I know that it's possible to get the element from event (v-on:click), but this is not an event, it's a simple method returning CSS class for the element according to few conditions of the viewmodel. It should be computable as well, but the problem is the same.
You can get the reference to your element in three ways
1. with Method Event Handlers (doc)
template:
<input type="text" v-model="dataField" v-bind:class="dataFieldClass" />
script:
dataFieldClass: function (e) {
const element = e.target;
}
2. with Inline Handlers (doc)
template:
<input type="text" v-model="dataField" v-bind:class="dataFieldClass($event, otherArgument)" />
script:
dataFieldClass: function (e, otherArgument) {
const element = e.target;
}
3. with Refs (doc)
template:
<input type="text" v-model="dataField" v-bind:class="dataFieldClass" ref="el"/>
script:
dataFieldClass: function () {
const element = this.$refs.el;
}
Maybe you could use ref?
<input type="text" v-model="dataField" v-bind:class="dataFieldClass" ref="el" />
And use it like this:
dataFieldClass: function () {
var elementId = this.$refs.el;
}
See documentation here: https://v2.vuejs.org/v2/api/#ref
What about using the ref pattern. Put ref="someName" in your DOM element, and access it in your method with this.$refs["someName"] (you can pass 'someName' as parameter to your method).
Note that's not a very good pattern except if for some reason you really need the DOM element. Otherwise just pass a relevant parameter to your method.
It's not a good method mainly because it has a major drawback: there is no $refs the first time the vue is rendered (because the element is not present yet). So you should force the vue to render twice.
If you have multiple elements inside a v-for loop, then this.$refs["someName"] becomes an array. You can get it to work with some adaptation, here is an example:
new Vue({
el: '#app',
data() {
return {
fields: [{
name: 'field1',
value: 'value1'
},
{
name: 'field2',
value: 'value2'
}
]
};
},
methods: {
dataFieldClass(index) {
if (!this.$refs.fields) {
// First render, the element is not there yet
return '';
} else {
// Here is the element
console.log(this.$refs.fields[index]);
}
}
},
mounted() {
// Force the instance to render a second time
this.$forceUpdate();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<label v-for="(field, index) in fields">
{{ field.name }}:
<input ref="fields" :value="field.value" v-bind:class="dataFieldClass(index)">
</label>
</div>
You can get the reference from DOM event object. "event.currentTarget" is the property that references the element where the event listener(vuejs method) assigned.
This is standard DOM specification, but you can also use this property in Vuejs.
dataFieldClass: function (event) {
var elementId = event.currentTarget.id;
}
A straightforward solution is to pass a reference to the element in the method to be called.
Here's what worked for me (a pretty basic example to help understand):
new Vue({
el: '#app',
data: {
msg: '',
},
methods: {
// in order to access the HTML element,
// add an argument (namely 'event') in the method definition,
// and access the element's current value by `event.target.value`
updateValue: function(event) {
this.msg = event.target.value;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input :value="msg" #input="updateValue" autofocus>
<br/>
<h2>
>>> {{ msg }}
</h2>
</div>
This seem to work for me, using ref (if element is nested another element)
<div ref="element">
vm.$refs.element
or $el if targeted element is the outermost
<template><div class="targeted-element">
this.$el
You can use refs as mentioned in other answers here.
Remember, refs cannot apply to computed objects. So be careful when using refs