I'm using a v-if in my parent to conditional render a child component.
Even when the child should not render the mounted function still gets executed and results in an error in console.
How does one makes sure the child component is rendered when launching a method when the child component is rendered.
In my case I'm using an autofocus:
mounted: function () {
// Autofocus input on load.
this.$nextTick(() => this.$refs.input.focus());
},
Error in nextTick: "TypeError: _this.$refs.input is undefined"
console.log(this.$refs.input) gives the object:
<input class="form-control" data-v-661f7e55="" type="text" autocomplete="off">
Try this.
<input class="form-control" ref="input" type="text" autocomplete="off">
mounted(){
this.$nextTick(() => this.$refs.input.focus())
}
This is working fine for me.ref is used to register a reference to an element or a child component.
Related
I've been getting null when I try to see what's inside an id with document.getElementById. Part of the code is below:
<input-layout v-if="edit" label="Status" class="grayout">
<u-select v-model='test.status' :options="testStatus" tabindex="14" class="grayout" id="testStatusDropDown"/>
</input-layout>
<input id="input1" type="checkbox">
Note that, v-if="edit" results in true.
In the mounted life cycle hook I have:
mounted () {
this.$nextTick(function (){
console.log(document.getElementById("input1"))
console.log(document.getElementById("testStatusDropDown"))
})
},
Originally I didn't have the console.log statements in the mounted method which resulted in null for both input1 and testStatusDropDown. I understand that because both elements do not exist yet when that part of the code runs. So then I moved them into the mounted method, now, I can see <input id="input1" type="checkbox"> but for the second log statement I get null.
I went to the vue js mounted api docs, which can be found here: https://v2.vuejs.org/v2/api/#mounted. From what I can see is that mounted does not guarantee all child components have been mounted so I need to use this.$nextTic inside the mounted method. However, even after adding this.$nextTick I'm still having the same issue where document.getElementById("testStatusDropDown") results in null when I expect it to be <u-select v-model='test.status' :options="testStatus" tabindex="14" class="grayout" id="testStatusDropDown"/>.
Is my expectation incorrect? What do I need to change such that document.getElementById("testStatusDropDown") does not return null?
Use ref to reference an element in vuejs.
<input id="input1" ref="input1" type="checkbox">
and in mounted access it using:
this.$refs.input1
I had a form component with the following content
function Form() {
return (
<div className="form-container">
<div className="form-control">
<label id="text-input">Text </label>
<input type="text"></input>
</div>
<div className="form-control">
<label>Time </label>
<input type="text"></input>
</div>
<div className="form-control" style={{alignItems:"center"}}>
<button className="add-but">Add</button>
</div>
</div>
)
}
I wanted to focus the text element after the component gets rendered.
I was first trying to put {document.querySelector("#txt-in").focus()}, it didn't work and after searching I found I could use the tag autoFocus. and everything would work beautifully.
But I was wondering, what if I want to actually execute javascript code after rendering? or actually do this in javascript? I found answers for class based components but couldn't find for function based components like the one I am using.
how do I execute code I want executed after the element is rendred, in function based components?
You can use React Hooks useEffect for your purpose.
Simply put below code
import React, {useEffect} from "react";
function Form() {
useEffect(() => {
// Do whatever you want after first render
// Put your code here
}, [])
}
Similar to what the components are writing, previously one would use functions likecomponentDidUpdate & componentDidMount to manipulate components after/before being rendered. Funcitonal components realised we could use one 'hook' for this called useEffect where one can trigger a particular action to occur on the basis of a state change to the component.
Here is a link to the docs for useEffect - https://reactjs.org/docs/hooks-effect.html
I'm trying to figure out why a call to this.setState isn't updating state.
I have the following lines method:
changeState(state, value){
this.setState({state:value}, ()=>console.log(this.state));
}
There are a few function using this, but one is a file upload component. Its a simple component that either renders a file input OR it renders an iframe, disabled input, and button. When the button is clicked I want to change the state in the parent component which then rerenders the file component and shows a file picker.
The call to this.setState seems to work ok, but when I console log state after it runs or if I stop execution before the next render takes place state is unaffected. My file upload component has a method like this:
renderField(field){
if(this.props.hasOwnProperty('file') && this.props.file){
return(
<div>
<iframe src={this.props.file} frameborder="0"> </iframe>
<input
disabled
placeholder={this.props.file}
name={field.name}
type='text'
/>
<span onClick={()=>this.props.changeFile(this.props.file_type, null)}>× Remove</span>
</div>
)
}else{
return(
<input
{...field}
type={field.type}
name={field.name}
onChange={(event) =>{
field.input.onChange(field.input.value = event.target.files[0])}
}
/>
)
}
}
when I call the method I get this output:
however after console logging my state is anything but changed:
You don't want to set the state property in your state, but the property name that state contains.
You can use a computed property name for this.
changeState(state, value) {
this.setState({ [state]: value }, () => console.log(this.state));
}
I'm learning vue.js and used vue-cli to setup a new project. Now I tried adding a method to a component but something is wrong:
<template>
<div>
<div v-for="task in $state.settings.subtasks">
<input type="text" v-model="task.text">
<input type="text" v-model="task.assignedTo">
<input type="button" v-on:click="removeTask(task)">
</div>
</div>
</template>
<script>
export default {
name: 'settings',
methods:{
removeTask:function(task){
console.log("remove task");
}
}
}
Clicking the button should call the removeTask function but it just outputs an error in the console:
[Vue warn]: Property or method "removeTask" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
found in
---> <Settings> at src/views/Settings.vue
<App> at src/App.vue
<Root>
What is wrong here?
When I went back to my question I noticed I was missing the </script> end tag. Adding that solved my problem.
I have something like this in my parent scope:
<form-error :errors="errors"></form-error>
<textarea class="form-control" name="post" cols="30" rows="8" #keydown="errors.clear('post')" v-model="post"></textarea>
Note the #keydown event, where I am clearing out the errors, by calling
method on a class.
With :errors="errors" I am passing instance of the below Errors class,
into <form-error> child component:
class Errors {
constructor() {
this.errors = {};
}
get(field) {
if (this.errors[field]) {
return this.errors[field][0];
}
}
clear(field) {
delete this.errors[field];
}
has(field) {
return this.errors.hasOwnProperty(field);
}
}
And in <form-error> child component I have this:
<template>
<div v-if="errors.has('post')" class="alert alert-danger" v-text="errors.get('post')"></div>
</template>
<script>
export default {
props: ['errors']
};
</script>
Now, while v-text="errors.get('post')" works fine, and I am getting error
displayed, the v-if="errors.has('post')" part doesn't work at all.
I am assuming errors is passed the right way as props, otherwise that
errors.get('post') wouldn't work.
Question is, why when parent triggers that #keydown event, and I see the
errors object is being emptied properly (Vue addon for chrome), the v-if
part doesn't update, thus hiding the div?
As you can see, the <FormError> child component is being updated to reflect the change in errors when I start typing, but still v-if doesn't trigger.
Edit
What's even more confusing, docs say:
Note that objects and arrays in JavaScript are passed by reference, so if the
prop is an array or object(as in my case), mutating the object or array itself inside the
child will affect parent state.
Although of course I am not mutating the object from with in my child, but the
important part is that object changes in parent should be reflected in child.
Are you getting any error. As I can see Map.has has poor support in browsers. You can try using any of following alternatives:
post in errors
<template>
<div v-if="'post' in errors" class="alert alert-danger" v-text="errors.get('post')"></div>
</template>
errors['post']
<template>
<div v-if="errors['post'] !== undefined" class="alert alert-danger" v-text="errors.get('post')"></div>
</template>