Why does javascript assume that a function is a variable? - javascript

Well, I just noticed that JS somehow takes a function as a variable in my code. Here is it:
<template>
<div id="">
<div>
<input type="text" v-model="value">
<button v-on:click='[factorial(), show=!show]'>Factorial</button>
<span v-show="show">{{value}}</span>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
value : 0,
show: false
}
},
methods: {
},
computed: {
factorial(x=this.value){
if (!x){return 1}
else {return x*factorial(x-1)}
}
},
mounted() {}
}
</script>
<style lang="scss">
</style>
The error is ReferenceError: Can't find variable: factorial.
What am I doing wrong?

You cannot pass arguments to computed properties, that is what methods are for.
You also need to use this when calling the function.
methods: {
factorial(x) {
if (!x) {
x = this.value;
}
return x * this.factorial(x-1);
},
},

You mustn't use factorial() as a computed function. You should instead make it a method:
<template>
<div id="">
<div>
<input type="text" v-model="value">
<button v-on:click='[factorial(), show=!show]'>Factorial</button>
<span v-show="show">{{value}}</span>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
value : 0,
show: false
}
},
methods: {
factorial(x=this.value){
if (!x){return 1}
else {return x * this.factorial(x-1)}
}
},
}
</script>
Here is a working sandbox for you:
https://codesandbox.io/s/lingering-voice-p6d9l

Related

Input values not resetting - vuejs

I have a level 2 input field component that i am using. I want to reset on button click from the parent component. I am trying to pass the data to base initial input field and then emitting back to the parent.
My question is that when i try to reset the data on button click the value from the parent component its not working.
Data is not set to null and the values remain as 123.
What wrong I am doing in the following code.
Any help would be appreciated.
Base Input
<template>
<input
v-model="myValue"
type="number"
inputmode="numeric"
#input="$emit( 'input', $event.target.value )"
/>
</template>
<script>
export default {
data () {
return {
myValue: undefined
};
}
}
};
</script>
Level 01
<template>
<div class="c-floating-label">
<input-number #input="passValue" />
</div>
</template>
<script>
import InputNumber from '../../atoms/form-controls/BaseInput';
export default {
components: {
InputNumber
}
methods: {
passValue: function (value) {
this.$emit('input', value);
}
}
};
</script>
Main Component
<div>
<level-01
:required="true"
:v-model="datax.cardNumber"
value="datax.cardNumber"
/>
<button #click="reset">click me</button>
</div>
<script>
data () {
return {
datax: {
cardNumber: undefined
}
};
},
created() {
this.datax.cardNumber = 123;
},
methods: {
reset () {
this.datax.cardNumber = null;
},
</script>
You missed binding on MainComponent
<level-01
:required="true"
:v-model="datax.cardNumber"
:value="datax.cardNumber"
/>
Note :value="datax.cardNumber" is correct
Second, in level-01 you do not bind value prop (not defined at all)
<template>
<div class="c-floating-label">
<input-number #input="passValue" :value="$attrs.value"/>
</div>
</template>
<script>
import InputNumber from '../../atoms/form-controls/BaseInput';
export default {
components: {
InputNumber
},
methods: {
passValue: function (value) {
this.$emit('input', value);
}
}
};
</script>
And finally BaseComponent:
<template>
<input
:value="$attrs.value"
type="number"
inputmode="numeric"
#input="$emit( 'input', $event )"
/>
</template>
<script>
export default {
data () {
return {
// myValue: undefined
};
}
}
};
</script>

How to pass value from Vue prompt to JS variable

I am using the Buefy UI Components and would like to pass on the $(value) outside the function to use it in an alert(thevalue) or something like that. Tried to find a solution out there, but haven't found a helpful one. So I am very thankful for your support on this!
<template>
<section>
<div class="buttons">
<button
class="button is-medium is-dark"
#click="prompt">
Launch prompt (default)
</button>
</div>
</section>
</template>
<script>
export default {
methods: {
prompt() {
this.$buefy.dialog.prompt({
message: `What's your name?`,
inputAttrs: {
placeholder: 'e.g. Walter',
maxlength: 10
},
trapFocus: true,
onConfirm: (value) => this.$buefy.toast.open(`Your name is: ${value}`)
})
}
}
}
</script>
You can store the value inside the data and call it later by other methods.
Haven't tested this yet, but it should work:
<template>
<section>
<div class="buttons">
<button
class="button is-medium is-dark"
#click="prompt">
Launch prompt (default)
</button>
</div>
</section>
</template>
<script>
export default {
data() {
return {
name: ""
}
},
methods: {
prompt() {
this.$buefy.dialog.prompt({
message: `What's your name?`,
inputAttrs: {
placeholder: 'e.g. Walter',
maxlength: 10
},
trapFocus: true,
onConfirm: (value) => {
// Set name
this.name = value;
this.$buefy.toast.open(`Your name is: ${value}`);
}
})
},
other() {
alert(this.name);
}
}
}
</script>

My component template can't find value property from <script> VueJS

So for some reason my app doesn't read my value variable that was defined in data. Not sure what's going on. Npm compiles this without any errors.
Here's the fiddle with my code:
https://jsfiddle.net/invinivi/yr164pb7/
<template>
<div id="exercise">
<div>
<p>Current Value: {‌{ value }}</p>
<button #click="value += 5">Add 5</button>
<button #click="value += 1">Add 1</button>
<p>{‌{ result }}</p>
</div>
<div>
<input type="text">
<p>{‌{ value }}</p>
</div>
</div>
</template>
<script>
export default {
name: 'Ex3',
el: '#exercise',
data: function () {
return {
value: 0
}
},
computed: {
result: function () {
return this.value == 37 ? 'done' : 'not there yet';
}
},
watch: {
result: function () {
var vm = this;
setTimeout(function () {
vm.value = 0;
}, 5000);
}
}
}
</script>
// FILE - Ex3.vue
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<Ex3/>
</div>
</template>
<script>
import Ex3 from "./components/Ex3"
export default {
name: 'App',
components: {
Ex3
}
}
</script>
The curly brackets had wrong encoding through Windows settings. After changing the settings to utf-8, everything runs fine.

How to call a method in a Vue component from programmatically inserted component

I'm trying to call a method from a child component which is programatically inserted.
Here is my code.
MultipleFileUploader.vue
<template>
<div class="form-group" id="multiple-file-uploader">
<div>
<multiple-file-uploader-part
:name="uploadername" :index="1"
#remove="deleteUploader" #fileselected="fileSelected($event)">
</multiple-file-uploader-part>
</div>
</div>
</template>
<script>
import MultipleFileUploaderPart from './MultipleFileUploaderPart.vue';
let index_count = 1;
export default {
components: {
'multiple-file-uploader-part':MultipleFileUploaderPart,
},
props: {
uploadername: {
type: String,
default: 'files',
}
},
data() {
return {
next_id:1,
}
},
methods: {
fileSelected: function (target) {
var UploaderPart = Vue.extend(MultipleFileUploaderPart);
new UploaderPart().$on('fileselected','fileSelected')
.$mount('#multiple-file-uploader');
},
deleteUploader: function (idToRemove) {
this.uploaders = this.uploaders.filter(
uploaders_id => {
return uploaders_id.id !== idToRemove;
}
)
}
},
}
</script>
<style scoped>
</style>
MultipleFileUploaderPart.vue
<template>
<div v-bind:id="name + '['+index+']'">
<div class="input-group margin">
{{index}}
<input type="file" accept="application/pdf,image/jpeg,image/png"
v-bind:name="name + '['+index+']'"
v-on:change="fileSelectedMethod($event.target)">
<div class="input-group-btn">
<button #click="removeClicked"
class="btn btn-danger btn-sm"
v-if="index != 1"
type="button">
Delete{{index}}
</button>
</div>
</div>
<p v-if="size_error" style="color: red">File size must be less than 2MB</p>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
},
index: {
type: Number,
},
},
data() {
return {
size: '',
size_error: false,
}
},
methods: {
removeClicked: function () {
document.getElementById(this.name+'[' + this.index + ']' ).remove();
this.$emit('remove', this.index);
},
fileSelectedMethod: function (target) {
this.size = target.files[0].size;
if (this.size < 2000000) {
this.size_error = false;
this.$emit('fileselected', target);
} else {
target.value = null;
this.size_error = true;
console.log(target.files);
}
}
}
}
</script>
<style scoped>
I'm trying to achieve is that when a file input is filled with a file, a MultipleFileUploaderPart is created. And when the file input element in this component is filled, another MultipleFileUploaderPart is inserted.
I'd like to call MultipleFileUploader 's fileSelected method from newly inserted components so that I can create another component.
I also want to remove a MultipleFileUploaderPart component when the delete button is clicked.
How can I achieve this? or is there a better way?
EDIT:
This is what I originally had.
MultipleFileUploader.vue
<template>
<div class="form-group">
<div>
<multiple-file-uploader-part
v-for="uploader in uploaders"
:name="uploadername" :index="uploader.id"
#remove="deleteUploader" #fileselected="fileSelected($event)">
slot
</multiple-file-uploader-part>
</div>
</div>
</template>
<script>
import MultipleFileUploaderPart from "./MultipleFileUploaderPart";
let index_count = 1;
export default {
//name: "MultipleFileUploader",
components: {MultipleFileUploaderPart},
props: {
uploadername: {
type: String,
default: 'files',
}
},
data() {
return {
uploaders: [
{
id: index_count++,
},
]
}
},
methods: {
fileSelected: function (target) {
if(target.value){
this.uploaders.push({
id: index_count++,
})
}
},
deleteUploader: function (idToRemove) {
this.uploaders = this.uploaders.filter(
uploaders_id => {
return uploaders_id.id !== idToRemove;
}
)
}
},
}
</script>
MultipleFileUploaderPart.vue
<template>
<div class="input-group margin">
{{index}}
<input type="file" accept="application/pdf,image/jpeg,image/png"
v-bind:name="name + '['+index+']'"
v-on:change="fileSelectedMethod($event.target)">
<div class="input-group-btn">
<button #click="$emit('remove',index)"
class="btn btn-danger btn-sm"
v-if="index != 1"
type="button">
Delete{{index}}
</button>
</div>
<br>
<p v-if="size_error" style="color: red">File size must be less than 2MB</p>
</div>
</template>
<script>
export default {
props: {
name: {
type: String,
},
index: {
type: Number,
},
},
data() {
return {
size: '',
size_error: false,
}
},
methods: {
checkFileSize: function () {
},
fileSelectedMethod: function (target) {
console.log(target);
console.log(target.files);
this.size = target.files[0].size;
console.log(this.size);
if (this.size < 2000000) {
this.size_error = false;
this.$emit('fileselected', target);
} else {
target.value = null;
this.size_error = true;
console.log(target.files);
}
}
}
}
</script>
And this happens. please click
When I click 'Delete'Button, correct child coponent is deleted but the file in the input form stays there. that's why I'm seeking for another approach.
Declare uploaders as an array of objects that contain all needed props for creation of MultipleFileUploaderPart.
Use v-for on MultipleFileUploaderPart in the main MultipleFileUploader to reactively generate MultipleFileUploaderPart components
Use $emit from MultipleFileUploaderPart to MultipleFileUploader to emit creation and deletion events so that MultipleFileUploader can add or remove elements in the uploaders array.
Please don't delete or create elements from DOM directly, let the VueJs do this work.

How to pass initial form values to child component in Vue.js?

I'm using Vue.js. From my template I include the child component (componentB) which includes several input elements. I want to initialize those input elements from my parent template. I found a way to do this (see code below). However, I'm wondering if this is a correct way, as the articles I have read so far use different approaches (e.g. with $emit):
https://simonkollross.de/posts/vuejs-using-v-model-with-objects-for-custom-components
https://zaengle.com/blog/using-v-model-on-nested-vue-components
https://alligator.io/vuejs/add-v-model-support/
Can you confirm that my code below matches the Vue.js design concepts or are there flaws?
<template>
<div>
<div class="md-layout">
<div class="md-layout-item md-size-100">
<ComponentB ref="componentB" v-model="componentB"></ComponentB>
</div>
</div>
</div>
</template>
<script>
import { ComponentB } from "#/components";
export default {
components: {
ComponentB
},
data() {
return {
componentB: {
textInputField: "my-initial-value"
}
};
},
methods: {
validate() {
return this.$refs.componentB.validate().then(res => {
this.$emit("on-validated", res);
return res;
});
}
}
};
</script>
<style></style>
Form componentB
<template>
<div>
<md-field
:class="[
{ 'md-valid': !errors.has('textInputField') && touched.textInputField },
{ 'md-form-group': true },
{ 'md-error': errors.has('textInputField') }
]"
>
<md-icon>label_important</md-icon>
<label>My text input</label>
<md-input
v-model="textInputField"
data-vv-name="textInputField"
type="text"
name="textInputField"
required
v-validate="modelValidations.textInputField"
>
</md-input>
<slide-y-down-transition>
<md-icon class="error" v-show="errors.has('textInputField')"
>close</md-icon
>
</slide-y-down-transition>
<slide-y-down-transition>
<md-icon
class="success"
v-show="!errors.has('textInputField') && touched.textInputField"
>done</md-icon
>
</slide-y-down-transition>
</md-field>
</div>
</template>
<script>
import { SlideYDownTransition } from "vue2-transitions";
export default {
name: "componentB",
props: ['value'],
components: {
SlideYDownTransition
},
computed: {
textInputField: {
get() {return this.value.textInputField},
set(textInputField) { this.$emit('input', { ...this.value, ['textInputField']: textInputField })}
}
},
data() {
return {
touched: {
textInputField: false
},
modelValidations: {
textInputField: {
required: true,
min: 5
}
}
};
},
methods: {
getError(fieldName) {
return this.errors.first(fieldName);
},
validate() {
return this.$validator.validateAll().then(res => {
return res;
});
}
},
watch: {
textInputField() {
this.touched.runnerName = true;
}
}
};
</script>
<style></style>
The simplest way to pass data to child component is to use props, which are then available in the child component and can pass the values back up to the parent.
https://v2.vuejs.org/v2/guide/components-props.html
// PARENT COMPONENT
<ComponentB :textInputField="textInputField" ...></ComponentB>
// CHILD COMPONENT
// TEMPLATE SECTION
<md-input
v-model="textInputField"
value="textInputField"
...
>
// SCRIPT SECTION
export default {
props: {
textInputField: String
}
}

Categories

Resources