How can I use the return value of a computed property inside a data element that is rendered as HTML?
I have a data element that is HTML, and it looks like this:
contractContent: `<p>Hi ${this.brideName},</p>`
I've also tried this:
contractContent: `<p>Hi {{this.brideName}},</p>`
I am trying to pass in the name via this computed property:
brideName() {
return this.returnContracts[0].brideName.split(' ')[0]
},
But all I'm getting is undefined. If I just put brideName on the component as a test, it returns the first name of the bride just fine.
Where did I go astray?
Here is a fiddle with my dilemma
data() is invoked on component creation and is not reactive. contractContent should be a computed prop for your code to work:
export default {
data() {
return {
name: "Martina Navratilova",
}
},
computed: {
brideName() {
return `<p>Hi ${this.name.split(' ')[0]},</p>`
},
contractContent() {
return `<p>Hi there ${this.brideName}</p>`
},
},
}
updated fiddle
Instead of going with data -> computed -> data -> render,
go directly with computed -> render (html)
In your template you can render html like this
<span v-html="brideName" />
assuming your data structure of returnContracts to be like this
data: {
returnContracts: [
{
"brideName": "Emma Watson"
}
]
}
Then you can directly render brideName from computed
brideName(){
// assuming you'll have correct data, if data isn't valid this will cause crash.
return `<p>Hi ${this.returnContracts[0].brideName.split(' ')[0]},</p>`
}
here is a fiddle to help you out implementation
Related
I'm trying to make a function where users can added multiple resume posts (from child component) to an array (in parent).
The problem is, every object I push to parent array stays reactive with the child form/object. So if I for example clear the form in child component, the Object I pushed to the parent array gets all it's values cleared as well. How to I emit and push the post-object to parent array and stop it from being reactive, so I can add new/more resume posts?
CreateProfile.vue
<template>
<ResumePostInput :resume_posts="form.resume_posts" #resumeHandler="handleResume"/>
</template>
<script>
export default {
data() {
form: {
resume_posts: []
}
}
methods: {
handleResume(post) {
this.form.resume_posts.push(post)
}
}
}
</script>
ResumePostInput.vue
<template
-- Input fields binded to post object --
</template>
<script>
export default {
emits: ["resumeHandler"],
props: {
resume_posts: Array
},
data() {
return {
post: {
title: '',
sub_title: '',
text: '',
year_from: '',
year_to: '',
type: ''
}
}
},
methods: {
addResume() {
this.$emit("resumeHandler", this.post)
}
}
}
</script>
you emit unknown property, it's a post, not posts
and learn about JS object, there are copy by reference & value
maybe you just need to update your addResume method like this
addResume() {
const post = JSON.parse(JSON.stringify(this.post))
this.$emit("resumeHandler", post)
}
It's not the problem that the object is reactive but that it's the same object because objects are passed by reference in JavaScript. If it's modified in one place, it's modified everywhere.
In order to avoid this, the object needs to be explicitly copied. For shallow object this can be done with object spread:
this.$emit("resumeHandler", {...this.post})
For deeply nested objects, multiple spreads or third-party clone function can be used.
I'm working on a vue cli project where items have two state equipped and unequipped.
This State is controlled by a Boolean located in the Props. Since you can switch the state I had to create a data isEquipped set to false by default.
I then added a watcher but it doesn't change my data value if my props is set to True.
Here's the code
name: "Item",
props: {
Index : Number,
name: String,
desc : String,
bonus: Array,
equipped : Boolean
},
data() {
return {
isEquipped : false
}
},
watch: {
equipped: function(stateEquipped) {
this.isEquipped = stateEquipped;
},
},
So for instance let's say I created a new item with equipped set to True, the watcher doesn't trigger and isEquipped stays at False, is there any reason to that ?
I came across multiple similar questions like this one Vue #Watch not triggering on a boolean change but none of them helped me
If you want to use watch then you can try define it as:
equipped: {
handler () {
this.isEquipped = !this.isEquipped;
},
immediate: true
}
This will change the value of this.isEquipped whenever the value of equipped will change.
I am not sure what is the use case of isEquipped but seeing your code you can use the props directly unless there is a situation where you want to mutate the isEquipped that is not related to the props.
Why not just use a computed value instead?
{
// ...
computed: {
isEquipped () {
// loaded from the component's props
return this.equipped
}
}
}
You can then use isEquipped in your components just as if it was defined in your data() method. You could also just use equipped in your components directly as you don't transform it in any way.
<p>Am I equipped? - <b>{{ equipped }}</b></p>
Watchers are "slow" and they operate on vue's next life-cycle tick which can result in hard to debug reactivity problems.
There are cases where you need them, but if you find any other solution, that uses vue's reactivity system, you should consider using that one instead.
The solution using a computed value from #chvolkmann probably also works for you.
There is a imho better way to do this:
export default {
name: "Item",
props: {
Index : Number,
name: String,
desc : String,
bonus: Array,
equipped : Boolean
},
data() {
return {
isEquipped : false
}
},
updated () {
if (this.equipped !== this.isEquipped) {
this.isEquipped = this.equipped
// trigger "onEquip" event or whatever
}
}
}
The updated life-cycle hook is called -as the name suggests- when a component is updated.
You compare the (unchanged) isEquipped with the new equipped prop value and if they differ, you know that there was a change.
In a Vue Js component, I need to loop through an object on the mounted hook that's in local storage in Vuex to update the data properties as you can see in code example.
I'm trying to update this.title, this.body, this.id whereby the rightHere variable in the loop is outputting these names as string values as the var you can see.
this.rightHere
...is the problem I know, and is obviously trying to target a data property "rightHere" which doesn't exist. But I don't know how else to overcome this in javascript and make rightHere output the string as needed? So how do I use this in a loop to dynamically change but tell Vue to update this. on each iteration?
data() {
return {
title: '',
body: '',
id: '',
}
},
mounted() {
for (var rightHere in this.$store.getters.getObject) {
if (this.$store.getters.getObject.hasOwnProperty(rightHere )) {
this.rightHere = this.$store.getters.getObject[rightHere ]
}
}
},
You would typically set the key in your template. It's a reserved word.
<div v-for='item in items' :key='$store.getters.getKey(item)'>{{item.title}}</div>
Suppose I have an array feedsArray, the example value may look like this:
this.feedsArray = [
{
id: 1,
type: 'Comment',
value: 'How are you today ?'
},
{
id: 2,
type: 'Meet',
name: 'Daily sync up'
}
]
Suppose I have registered two components: Comment and Meet, Each component has a prop setting as the following:
props: {
feed: Object
}
and the main component has the following definition:
<component v-for="feed in feedsArray" :feed="feed" :key="feed.id" :is="feed.type"></component>
As you can see, it uses is property to select different component. My question is, how to detect feed object change in the child component ? Like when I set
this.feedsArray[0] = {
id: 1,
type: 'Comment',
value: 'I am not ok'
}
How can the Comment component detect the changes ? I tried to add a watcher definition in the child component like the following:
watch: {
feed: {
handler (val) {
console.log('this feed is changed')
},
deep: true
}
},
But it doesn't work here. Anyone know how to solve this ?
Do not assign directly to an array using index - use splice() instead, otherwise JavaScript can not detect that you have changed the array.
If you want to change only the value of an already existing key of an object - then simply update it e.g. this.feeds[0].value = 'I am not okay any more';
This works for existing keys only - otherwise you have to use this.$set(this.feeds[0], 'value', 'I am not okay any more');
I'm working on an Ember project in which I have to specify the parameters of the component dynamically.
I have the following array in the .js controller:
componentParams: ["id", "name"]
What I want to do is to take the values in the array and use them in handlebars as the component parameter like this
{{component-name id=somevalue name="somevalue"}}
Could this be done?
An approach I use.
controller.js
navbarParams: {
titleToShow: 'General.ResearchProjects',
glyphicon: 'glyphicon glyphicon-globe',
infoText: 'information/project'
},
template.hbs
{{my-navbar params=navbarParams}}
my-navbar.hbs
<h1> {{params.titleToShow}} <span class={{params.glyphicon}}> </span> </h1>
If your parameters are queryParams
They should be defined like that
queryParams: ['foo', 'bar',],
foo: null,
bar: null
{{my-navbar first=foo second=bar}}
Honestly it depends, if you are stuck with that array - you can use computed properties to extract the proper array values. ( This is probably not recommended - a better approach would be to format your componentParams into an object ( like #kristjan's example).
If you are stuck with the array - and the positions will never change ( id will always be componentParams[0] & name will always be componentParams[1], you could try something like this ::
// controller
import Ember from 'ember';
const {
Controller,
computed,
get
} = Ember;
export default Controller.extend({
componentParams: ['id', 'name'],
componentName: computed('componentParams', {
get() {
return get(this, 'componentParams')[1];
}
}),
componentId: computed('componentParams', {
get() {
return get(this, 'componentParams')[0];
}
})
});
// template
{{my-component name=componentName id=componentId}}
// component/template
name:: {{name}}
<br>
id :: {{id}}
check out this twiddle for a working example
Does this help ??