Property "xxx" was accessed during render but is not defined on instance - vuejs3

this is part of js
...
data() {
return {
lineList: [],
}
},
...
created(){
await this.getLineList()
}
...
getLineList(){
...
//use axios to get data
this.lineList = res.data
...
}
this is part of temlate
...
<el-form-item label="line">
<el-select
v-model="searchInfo.id"
default-first-option
placeholder="select line"
>
<el-option
v-for="item in lineList"
:key="item.id"
:label="item.name"
:value="item.id"
:value-key="id"
/>
</el-select>
</el-form-item>
...
And console a lot of warning, like: Property "xxx" was accessed during render but is not defined on instance.
How to avoid warning?

created()is a hook function but your custom methods should be declared in the "methods" property
...
methods: {
getLineList(){
...
}
}

Related

VUE3 - Select element on mounted() or created() in a custom component without using "event"

i have a custom input component and i want to select it without clicking on it or something so i cant use "event", i want to select it on created() or mounted()
how can i do that?
<template>
<div class="form-control">
<label :for="id">
{{ label }}
</label>
<input
:id="id"
:type="mode"
:value="currentValue"
#input="$emit('update:modelValue', $event.target.value)"
#focus="pullLabel"
#blur="pushLabel"
/>
</div>
</template>
<script>
export default {
created() {
this.test();
},
methods: {
test() {
console.log(this); // -> How could this be like '<input id="title" type="text">'
},
},
};
</script>
I figured it out myself after 6~ hours of work.
The answer is $refs
I sent a "ref" from parent component like this:
<form ref="settingsForm" #submit.prevent="updateConfig">
Then in methods, i selected all the inputs in form like this: (except submit input)
methods: {
...
focusInput() {
const inputs = this.$refs.settingsForm.querySelectorAll(
'input:not([type="submit"])'
); // $refs.settingsForm -> comes from the parent element, you can name "settingsForm" whatever you want
Array.from(inputs).map((e) => {
if (e.value.length > 0) {
e.previousElementSibling.classList.add("clicked-input");
}
});
},
...
}
By the way, the most important thing is, you have to call the function on mounted() method, not on created()

How can I make vuefire show loading screen?

As title
Vuefire can auto get data from firebase database, but it needs some loading time.
So I want to display some css animation before data being fetched, is there any event can I $watch when it successed
The readyCallback approach in the other answer didn't work for me. I got an error document.onSnapshot is not a function.
Instead, I used the binding approach to set a flag when loading is complete.
<script>
// ...
export default {
data() {
return {
data: [],
loaded: false,
}
},
mounted() {
this.$bind('data', firebase.firestore().collection('someDocRef'))
.then(() => this.loaded = true);
},
}
</script>
Then my template can have conditionally-rendered loading screens:
<template>
<template v-if="!loaded">
<p>Loading...</p>
</template>
<template v-if="loaded">
<!-- Display data here -->
</template>
</template>
You can do this multiple ways.
Vuefire has readyCallback out of the box which is callback called when the data is fetched (ready).
Here it is:
var vm = new Vue({
el: '#demo',
data: function() {
return {
loaded: false
}
}
firebase: {
// simple syntax, bind as an array by default
anArray: db.ref('url/to/my/collection'),
// can also bind to a query
// anArray: db.ref('url/to/my/collection').limitToLast(25)
// full syntax
anObject: {
source: db.ref('url/to/my/object'),
// optionally bind as an object
asObject: true,
// optionally provide the cancelCallback
cancelCallback: function () {},
// this is called once the data has been retrieved from firebase
readyCallback: function () {
this.loaded = true // NOTE THIS LINE
}
}
}
})

Access ReactiveVar // Template.instance() from helper (indirectly)

How can I access ReactiveVar in the construction like below?
Template.profile.helpers({
user: {
...
gender: () => Template.instance().genderFlag.get(), //returns Uncaught TypeError: Cannot read property 'genderFlag' of null
...
},
});
Returns error because Template.instance() inside gender: is null (when I console.log(Template.instance());)
This is how I create ReactiveVar:
Template.profile.onCreated( function() {
this.genderFlag = new ReactiveVar(0);
});
P.S. gender is inside user because I use user context i.e. {{#with user}} in my .html.
UPDATE:
Spacebars part:
<button type="button" name="Male" class="{{#if gender '1'}}gender--selected{{/if}}">Male</button>
<button type="button" name="Female" class="{{#if gender '2'}}gender--selected{{/if}}">Female</button>
so I am passing arg to the Template.helper gender:
user: {
...
gender: (arg) => arg == Template.instance().genderFlag.get(),
...
}
Because you are creating a function within the helper it seems to be picking up the wrong data context and therefore the Template variable is not available a the time it is called, the following code works, it moves the function to the helper itself so the context is correct and it can access Template.instance() correctly, then you can return an object for user as needed for your #with
Template.profile.helpers({
user: () => {
return {
...
gender: Template.instance().genderFlag.get()
...
};
}
});
EDIT:
In line with the update to your question, couple of options but neatest I would say is:
Template.profile.helpers({
user: () => {
var gend = Template.instance().genderFlag.get();
return {
...
gender: gend,
isMale: gend===1?"gender--selected":"",
isFemale: gend===2?"gender--selected":"",
...
};
}
});
And in your handlebars
<button type="button" name="Male" class="{{isMale}}">Male</button>
<button type="button" name="Female" class="{{isFemale}}">Female</button>

This is not set in my template?

I have a problem what looks like that this is not being set within my template. This didn't happen before, and I don't know what is changed.
My router.js
Router.map(function() {
this.route('gameRoom', {
path : '/game/:_id',
controller : GameRoomController
});
Controller
GameRoomController = RouteController.extend({
template : 'DetailsSubmit',
waitOn : function() {
return [
Meteor.subscribe('gameList', this.params._id),
Meteor.subscribe('gameInfo', this.params._id),
Meteor.subscribe('hintsList', this.params._id),
Meteor.subscribe('guessList', this.params._id),
Meteor.subscribe('imagesList', this.params._id),
Meteor.subscribe('allUsers')
// Meteor.subscribe('scoreList', this.params._id)
// stil in development will optimize this later
];
},
data : function() {
return Games.findOne(this.params._id);
}
});
So in my detailsubmit.html I have the following template (snippit)
<template name='DetailsSubmit'>
{{#if isWaitingOnAction}}
<div id="profileInfo">
<img src="http://placehold.it/90x90" alt=""/>
</div>
{{/if}}
</template>
If i type Games.find().fetch() it will output correctly:
_id: "5DDCNfWiBeHG4o7nQ"
active: true
finished: false
players: Array[2]
round: 0
theBoss: "JLApNut5rTpRxoL9S"
thePlayer: "o5aJETfWQTjEkZprf"
__proto__: Object
So I would expect my template would work correctly if I try one of the following commands:
And my helper:
Template.DetailsSubmit.helpers({
isWaitingOnAction: function() {
console.log(this) // return Object {}
console.log(Games.findOne(this._id)) // returns undefined in console
console.log(Meteor.userId()); // returns correct userId
}
})
What am I missing here?
Replace:
return Games.findOne(this.params._id);
with:
return Games.findOne({_id:this.params._id});

Native 'change' event when using Select2 in Meteor.js?

I am using the select2 package from atmosphere in my Meteor.js-project. I am however unable to get the native 'change' to my event-handler in the template. I need this to access the object context in the template.
This does not fire when changing the select value in a Select2-select box:
Template.myTemplate.events({
'change .newValue' : function () {
console.log("I am not fired :(");
console.log("But I can access this. :)", this);
}
}
This, however, does work. The only problem is that I can't access the "this" context from the template, which is what I need.
Template.myTemplate.rendered({
var self = this.data;
$('.newValue')
.select2()
.on('change', function () {
console.log("I am fired! :)");
console.log("I can access self, and get the currently logged in user", self);
console.log("But that is not what I want. :(");
}
}
Select2 rewrites the <select> tag into a series of <div>s, so you don't actually have a change event for the native event handler to grab.
What you could do is stash the _id property of your template data in the id of your select2 element. Your select2 on change listener passes a jQuery event and using it's target you can recreate the missing context. It's ugly but works.
Edit:
What I mean is put the Mongo document _id into the html element id field, like so:
template.html
//...
{{#each dropdown}}
<select id="{{_id}}" class="select2">
{{#each options}}<option value="{{ serialNo }}">{{ name }}</option>{{/each}}
</select>
{{/each}}
//...
template.js
Template.template.rendered = function () {
$('select2').select2({
// ...
}).on('change', function (e) {
console.log(e.target);
});
// ...
Template.template.dropdown = function () {
return Dropdowns.find();
}
Assuming your dropdown document was something like:
{
"_id" : "7MzpRfzyCDTgz4QXJ",
"name" : "dropdown1",
"options" : [
{
"serialNo" : 1,
"name" : "Option 1"
} , {
"serialNo" : 2,
"name" : "Option 2"
}
]
}

Resources