getElementById inside the vue js mounted life cycle hooks results in null - javascript

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

Related

Vue3 v-model bind nested data property with bracket access fails

I am using Vue3 and facing problem that I cannot bind nested property to v-model correctly.
Here is source code:
Template:
<div id="app">
<span>{{level1.level2.level3}}</span> <br/>
<span>{{level1['level2']['level3']}}</span> <br/>
<input v-model="level1.level2.level3" /> <br/>
<input v-model="level1.level2['level3']" /> <br/>
<input v-model="level1['level2']['level3']" />
</div>
JS
Vue.createApp({
data() {
return {
level1: {
level2: {
level3: "val"
}
}
}
},
methods: {}
}).mount("#app")
<input v-model="level1.level2.level3" /> bind works
<input v-model="level1.level2['level3']" /> bind works
but <input v-model="level1['level2']['level3']" /> bind fails
The console warning said
"[Vue warn]: Template compilation error: v-model value must be a valid JavaScript member expression.
What's the reason level1['level2']['level3'] not binding to v-model correctly? I think it's a valid js expression.
Here is online fiddle
It looks like this is an issue with Vue itself, not with your code. It also seems that this issue has been fixed in a commit just over a week ago.
So if you're on Vue <=3.1.1 (a.k.a any version but the current GitHub master branch), your only real solution here would be to rework how you access properties, wait for a Vue update, or depend directly on the GitHub repository's master branch (not a great idea in general, so only do this if you need this notation and you need it right now).

React run javascript code after all render is completed in function based component

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

launch method after child component has been rendered

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.

Vue.js component method "not defined on the instance"

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.

child not updating based on props in Vue.js

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>

Categories

Resources