Custom component , error compiling template - javascript

What am I doing wrong here with my custom component?
What I want is to have:
label
input
Why is idfor undefined? Why do I get this error on labeltext
invalid expression: Unexpected identifier in "Name of superhero"
labeltext is supposed to be a string and I should be able to pass in any string I like?
This is what I have so far. jsfiddle
Vue.component("base-input", {
props: {
value: {
type: String,
required: true
},
idfor: {
type: String,
required: true
},
labeltext: {
type: String,
required: true
}
},
template:
`
<div>
<label for="idfor">{{labeltext}}</label>
<input type="text" id="idfor" v-bind:value="value" v-on:input="$emit('input', $event.target.value)">
</div>
`
});
Vue.config.devtools = true;
new Vue({
el: "#app",
data() {
return {
user: {
name: "Hulk",
age: 42
}
};
}
});
HTML
<div id="app">
<base-input v-bind:idfor="name" v-bind:value="user.name" v-bind:labeltext="Name of superhero"/>
</div>

there's one problem, you just have to make sure you are including '' for literals
<div id="app">
<base-input v-bind:idfor="'name'" v-bind:value="user.name" v-bind:labeltext="'Name of superhero'"/>

This is because v-bind:labeltext= evaluates the value as an expression. And if you need to pass an string then you need to wrap it in quotes like
v-bind:labeltext="'Name of superhero'"
Updated fiddle

Related

how to v-model on different array vue 3

Hi I was trying to use a v-model an input to a value in object in an array of object in Vue 3. The complexity lies in the fact the object is first processed by a function. And that it need to be processed every time when a change is made to an input. Here is my code (and a sandbox link) :
<template>
<div id="app">
<div v-for="param in process(parameters)" :key="param">
Name : {{param.name}} Value : <input v-model="param.value">
</div>
{{parameters}}
</div>
</template>
<script>
export default {
name: "App",
data(){
return{
parameters :[
{'name':'Richard Stallman','value':'cool dude'},
{'name':'Linus Torvalds','value':'very cool dude'},
{'name':'Dennis Ritchie','value':'very very cool dude'}
]
}
},
methods:{
process(parameters){
const results = parameters.map( param =>{
return {name:param.name+' extra text',
value:param.value+' extra text',
}
})
return results
}
}
};
</script>
I just want the original parameters to change when something is types in the inputs. Maybe #change could be of use. But I didn't find a fix with #change. Does anyone know a solution to my problem? Thanks in advance.
Use computed property to get reactive state of the data.
Working Demo :
new Vue({
el: '#app',
data: {
parameters :[
{'name':'Richard Stallman','value':'cool dude'},
{'name':'Linus Torvalds','value':'very cool dude'},
{'name':'Dennis Ritchie','value':'very very cool dude'}
]
},
computed: {
process() {
const results = this.parameters.map((param) => {
return {
name: param.name + ' extra text',
value: param.value + ' extra text'
}
});
return results;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="param in process" :key="param">
Name : {{param.name}}
Value : <input v-model="param.value">
</div><br>
<strong>Orinigal Data :</strong> {{parameters}}
</div>
I am not entirely sure I understood whether the person should be able to see/edit the text you added within you processing method.
Anyway, I think this sample of code should solve you problem :
<template>
<div id="app">
<div v-for="param in parameters" :key="param.name">
Name : {{ param.name }} Value : <input v-model="param.value" />
</div>
{{ process }}
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
parameters: [
{ name: "Richard Stallman", value: "cool dude" },
{ name: "Linus Torvalds", value: "very cool dude" },
{ name: "Dennis Ritchie", value: "very very cool dude" },
],
};
},
computed: {
process: function() {
const results = this.parameters.map((param) => {
return {
name: param.name + " extra text",
value: param.value + " extra text",
};
});
return results;
},
},
};
</script>
So, we're iterating through the parameters array directly, adding an input on the value just like you did.
When you type in the input, you update the parameter linked to it, in live.
I just switched the method you made into a computed method.
This way, every time parameters is updated, "process" is also updated because it's depending on it directly.
I also removed passing the "parameters" argument, it's in the component data, you can just access it directly.
This way, using "process" just like any variable, you'll always have the updated parameters + what you added to em.

Why if I get the object property within the computed object gets undefined but not the object itself? Which approach fits better in this context?

My Greeting.
To put in context, my purpose of asking this question is to be able to render a child component inside a form based on the selected option of the <app-selector> Vue component as simple and silly as that.
For the sake of simplicity. I've made a snippet down here to expose what I'm trying to figure out.
Basically, the aim is to get the component name to be rendered by using the computed property cardTypeComponent. However, I want to fathom the way cardTypeComponent is working, since I cannot see why, in one hand, the first return (return this.form) is giving the object (this.form) with the property I want (card_type) but on the other hand the second return (return this.form.card_type ? this.form.card_type + 'Compose' : '') is giving me an empty string, assuming this.form.card_type is undefined when it is clear looking at the first return that, in fact, is not taking it as undefined.
There is way more context, since once the option is selected there is a validation process from the server before setting the value inside this.form object. Moreover, the form interaction is through steps, so once the user select the option he has to click a button to reach the form fields that corresponds to that type card selected, therefore the component is not going to be rendered the very first moment the user selects an option as in the snippet approach. However, it would entangle what I'm asking. Thanks beforehand.
It is better to use the Fiddle link below.
Snippet
var appSelector = Vue.component('app-selector', {
name: 'AppSelector',
template: `<div>
<label for="card_type">Card Type:</label>
<select :name="name" value="" #change="sendSelectedValue">
<option v-for="option in options" :value="option.value">
{{ option.name }}
</option>
</select>
</div>`,
props: {
name: {
required: false,
type: String,
},
options: {
required: false,
type: Array,
}
},
methods: {
sendSelectedValue: function(ev) {
this.$emit('selected', ev.target.value, this.name)
}
}
});
var guessByImageCompose = Vue.component({
name: 'GuessByImageComponse',
template: `<p>Guess By Image Compose Form</p>`
});
var guessByQuoteCompose = Vue.component({
name: 'GuessByQuoteComponse',
template: `<p>Guess By Quote Compose Form</p>`
});
new Vue({
el: '#app',
components: {
appSelector: appSelector,
guessByImageCompose: guessByImageCompose,
guessByQuoteCompose: guessByQuoteCompose,
},
data() {
return {
form: {},
card_types: [
{
name: 'Guess By Quote',
value: 'GuessByQuote'
},
{
name: 'Guess By Image',
value: 'GuessByImage'
}
],
}
},
computed: {
cardTypeComponent: function() {
return this.form; // return { card_type: "GuessByImage" || "GuessByQuote" }
return this.form.card_type ? this.form.card_type + 'Compose' : ''; // return empty string ("") Why?
}
},
methods: {
setCardType: function(selectedValue, field) {
this.form[field] = selectedValue;
console.log(this.form.card_type); // GuessByImage || GuessByQuote
console.log(this.cardTypeComponent); // empty string ("") Why?
}
},
mounted() {
console.log(this.cardTypeComponent); // empty string ("")
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form action="#" method="post">
<app-selector
:name="'card_type'"
:options="card_types"
#selected="setCardType"
>
</app-selector>
{{ cardTypeComponent }} <!-- Always empty string !-->
<component v-if="cardTypeComponent !== ''" :is="cardTypeComponent">
</component>
</form>
</div>
https://jsfiddle.net/k7gnouty/2/
You're setting a property on this.form which is not initialized first in data. This means you have run into Vue's change detection caveat. Use Vue.set when setting it:
methods: {
setCardType: function(selectedValue, field) {
Vue.set(this.form, field, selectedValue);
}
}
Alternatively, you could declare the properties first if that works better for you.

Vue email validation is not returning true

I am really new to Vue and for this project I am using email validation followed by reg on VUE Script Data. When I print out the console.log(this.reg.test(this.email)) , while the user is filling the email input field, it validates correctly as true or false. NEXT button stays disable for both true and false case. Can we make the button enable, once the console.log(this.reg.test(this.email)) is true.
View
<div id="app">
<h2>Todos:</h2>
<input type="email" v-model="email" placeholder="enter email email address"/>
<button v-bind:disabled="isDisableComputed">NEXT</button>
</div>
Script
new Vue({
el: "#app",
data: {
email: '',
reg: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,24}))$/
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
},
computed: {
isDisableComputed() {
if(this.reg.test(this.email) == 'true'){
console.log(this.reg.test(this.email));
return false;
}
else{
console.log(this.reg.test(this.email));
return true;
}
},
}
})
Below is my code uploaded on JSFIDDLE
https://jsfiddle.net/ujjumaki/9es2dLfz/6/
Look into MDN: RegExp, RegExp.test return boolean, not one string. So this.reg.test(this.email) == 'true' will be always false.
let regex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,24}))$/
console.log("regex.test('test#test.com') ==> ", regex.test('test#test.com'))
console.log("regex.test('test#test.com')=='true' ==> ", regex.test('test#test.com') == 'true')
console.log("regex.test('test#test.com') ==> ", regex.test('test#test#.com'))
console.log("regex.test('test#test#.com')=='true' ==> ", regex.test('test#test#.com') == 'true')
So uses return !this.reg.test(this.email) instead like the computed property=isDisableComputed in below snippet.
new Vue({
el: "#app",
data () {
return {
email: '',
reg: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,24}))$/
}
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
},
computed: {
isDisableComputed() {
return !this.reg.test(this.email)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<input type="email" v-model="email" placeholder="enter email email address"/>
<button :disabled="isDisableComputed">NEXT ({{isDisableComputed}})</button>
</div>

VueJS2: Control logic using JSON?

I am a newbie to JavaScript. I am trying to figure out what is the best way to write the control logic for my application. I have a list of checkboxes that hide and show different elements depending on certain options that are checked.
For example, I have the following HTML:
<label>
<input type="checkbox" name="productType" value="magazines" v-model="selectedProductType"> Magazines
</label>
<label>
<input type="checkbox" name="productType" value="books" v-model="selectedProductType"> Books
</label>
<label>
<input type="checkbox" name="productType" value="comics" v-model="selectedProductType"> Comics
</label>
<label>
<input type="checkbox" name="productType" value="videos" v-model="selectedProductType"> Videos
</label>
...snip...
And then I am hiding/showing things based on the checkmarked items
above, like so (this is just one example of some of the conditions I need to check):
<section v-if="(selectedOffice.jira) && (selectedProductType == 'comics') || (selectedProductType == 'videos')" id="booksInfo">Some info here</section>
...snip...
The issue is that I have to check different values in the data/model that looks like this:
//selectedOffice: '',
selectedProductType: [],
officeList: [
{
code: 'Blue Office',
jira: true
},
{
code: 'Red Office',
jira: false
}
...snip...
],
productList: [
{
type: 'comics',
url: 'www.comicsurl.com'
},
{
type: 'videos',
url: 'www.videosurl.com'
}
....snip...
]
Does anyone have any advice on the best way to approach the logic for my application? Better flexibility? My plan is to use an API for the data (Wordpress JSON REST API) and I will be able to customize the key/value properties on my own, but need help with the conditional stuff.
Thanks for any help!
Instead of using v-model, use #click or v-on:click to handle the click event instead. I like to keep most logic inside Vue instead of in the HTML so I recommend making use of methods and computed to determine what data to show.
const app = new Vue({
el: '#app',
data: {
selectedProductTypes: {
magazines: false,
books: false,
comics: false,
videos: false
},
productList: [],
typeList: [
{
type: 'magazines',
name: 'Magazines',
text: 'Check out new magazines'
},
{
type: 'books',
name: 'Books',
text: 'Check out new books'
},
{
type: 'comics',
name: 'Comics',
text: 'Check out new comics'
},
{
type: 'videos',
name: 'Videos',
text: 'Check out new videos'
}
]
},
computed: {
dataToBeShown() {
return this.productList
.filter(product => this.selectedProductTypes[product.type] === true) || [];
}
},
created() {
// get json data here
// assignning data here for demo
this.productList = [
{
type: 'magazines',
url: 'www.magazineurl.com'
},
{
type: 'books',
url: 'www.booksurl.com'
},
{
type: 'comics',
url: 'www.comicsurl.com'
},
{
type: 'videos',
url: 'www.videosurl.com'
}
]
},
methods: {
selectProductType(input) {
this.selectedProductTypes[input] = !this.selectedProductTypes[input];
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<div class="control">
<div v-for="item in typeList">
<label>
<input type="checkbox" #click="selectProductType(item.type)"> <b>{{item.name}}</b>&nbsp<span>{{item.text}}</span>
</label>
</div>
</div>
<hr/>
<section v-for="item in dataToBeShown">
<div>Type: {{item.type}}</div>
<div>Url: {{item.url}}</div>
</section>
</div>

Passing Parent Function to Child Component in VueJS

I'm having my practice in VueJS 1.0 and I am learning about Components.
in this example, there is an input element and has to supply coupon or some kind of a code from an API. and I have to validate. I have my <coupon > component and has props of when-applied. The when-applied must call the parent function setCoupon but it won't.
I only got this error this.whenApplied is not a function.
<div id="demo" class="list-group">
<script id="coupon-template" type="x-template">
<input type="text" v-model="coupon" v-on:blur="whenCouponHasBeenEntered">
<div v-text="text"></div>
</script>
<coupon when-applied="setCoupon"></coupon>
</div>
Here is my app.js file
Vue.component('coupon', {
template: '#coupon-template',
props: ['whenApplied'],
data: function() {
return {
coupon: '',
invalid: false,
text: ''
}
},
methods: {
whenCouponHasBeenEntered: function() {
this.validate();
},
validate: function() {
if( this.coupon == 'FOOBAR') {
this.whenApplied(this.coupon);
return this.text = '20% OFF!!';
}
return this.text = 'that coupon doesn`t exists';
}
}
});
new Vue({
el: '#demo',
methods: {
setCoupon: function(coupon) {
alert('set coupon'+ coupon);
}
}
});
Someone pls help. Suggestions pretty much appreciated.
You should bind the property:
<coupon v-bind:when-applied="setCoupon"></coupon>
or you could use the shorthand syntax for v-bind:
<coupon :when-applied="setCoupon"></coupon>
Read more about the props here.

Categories