Displaying a specific data in html ionic - ionic4

I'm trying to display a specific username using the user uid in firebase, but i can't display it in the html. I try to get the username from the userColl by the Uid. For the html, i tried using *ngFor, but there's problem indicating that it can only be used for array
Here's is the code:
read_Username() {
return this.firestore.collection('userColl',ref => ref
.where('userUid', '==', this.userUid)).snapshotChanges();
//return this.firestore.collection('/userColl/userUid' + this.userUid).snapshotChanges();
}
ngOnInit() {
this.user = firebase.auth().currentUser;
//this.userUid = firebase.auth().currentUser.uid
this.read_Username().subscribe(data => {
this.user = data.map(e => {
if(this.user != null){
return {
id: e.payload.doc.id,
userUid: e.payload.doc.data()['userUid'],
username: e.payload.doc.data()['username'],
};
}
})
console.log(this.user);
});
}
The html:
<ion-card class="welcome-card">
<img src="/assets/shapes.svg" alt=""/>
<div>
<ion-card-header >
<ion-card-subtitle></ion-card-subtitle>
<ion-card-title> {{userUid}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<p>{{username?.username}}</p>
</ion-card-content>

Try changing your codes to this:
read_Username() {
return this.firestore.collection('userColl',ref => ref
.where('userUid', '==', this.userUid)).snapshotChanges();
//return this.firestore.collection('/userColl/userUid' + this.userUid).snapshotChanges();
}
userUid:string;
username:string;
ngOnInit() {
this.user = firebase.auth().currentUser;
//this.userUid = firebase.auth().currentUser.uid
this.read_Username().subscribe(data => {
this.user = data.map(e => {
if(this.user != null){
return {
id: e.payload.doc.id,
userUid: e.payload.doc.data().userUid,
username: e.payload.doc.data().username,
};
}
})
console.log(this.user);
});
}
The html:
<ion-card class="welcome-card">
<img src="/assets/shapes.svg" alt=""/>
<div>
<ion-card-header >
<ion-card-subtitle></ion-card-subtitle>
<ion-card-title>{{userUid}}</ion-card-title>
</ion-card-header>
<ion-card-content>
<p>{{username}}</p>
</ion-card-content>
If it doesn't work, change the
userUid: e.payload.doc.data().userUid,
username: e.payload.doc.data().username,
to:
userUid: e.payload.doc.data()['userUid'],
username: e.payload.doc.data()['username'],

Related

Cannot update the user profile. (Laravel 8 & Vue.js 2)

I am naive of Laravel and Vue.js. I'm using JWT authentication for my backend and VueX for the frontend.
I want the user able to change their picture, name and email but I got an error when I try to save. and for your information, I try to edit and save name and email first, update the picture will do after this.
My Profile page
and this is the error that I received.
here is my code:
<template>
<div class="container" style="padding-top:25px">
<div class="main-font">My Profile</div>
<div class="d-flex row">
<div class="col-6">
<ValidationObserver v-slot="{ handleSubmit }">
<form #submit.prevent="handleSubmit(updateProfile)">
<div class="d-flex py-4">
<!-- <img class="profile" src="/img/profile.jpg" alt="" > -->
<div>
<template v-if="!currentUser.profile_image_url" >
<img class="profile" src="/img/default.png" alt="">
</template>
<template v-else>
<div class="profile">{{currentUser.profile_image_url}}</div>
</template>
</div>
<div class="my-auto ml-5">
<button type="submit" class="btn upload text"><i class="fas fa-upload fa-sm pr-2"></i>Upload new picture</button>
</div>
</div>
<div class="form-group col-10 p-0 m-0">
<ValidationProvider name="Name" rules="required|alpha" v-slot="{ errors }">
<label class="text">Name</label>
<input type="text" id="name" class="form-control form-text" placeholder="Enter your username" v-model="userForm.name">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<div class="form-group col-10 p-0 m-0 mt-4">
<ValidationProvider name="E-mail" rules="required|email" v-slot="{ errors }">
<label class="text">Email</label>
<input type="email" id="email" class="form-control form-text" placeholder="Enter email" v-model="userForm.email">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<button type="submit" class="btn col-10 p-o save-but">SAVE CHANGES</button>
</form>
</ValidationObserver>
</div>
<div class="w-50">
<img class="bg-img" src="/img/profile-bg.png" alt="">
</div>
</div>
</div>
script:
<script>
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate/dist/vee-validate.full';
export default {
components: {
ValidationProvider,
ValidationObserver,
},
data() {
return {
userForm: {
name: '',
email: '',
},
error: null,
}
},
watch: {
created () {
this.userForm = JSON.parse(JSON.stringify(this.$store.getters.currentUser));
},
computed: {
currentUser(){
return this.$store.getters.currentUser;
},
},
methods: {
// updateProfile (){
// this.$store.dispatch('updateUser');
// var _this = this;
// // ajax call to POST this.profile then
// _this.$store.commit('update',
// {
// // name: 'currentUser',
// data: this.userForm
// })
// },
getUser (){
const token = localStorage.getItem('token')
axios.get('/api/auth/userprofile',{
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => {
this.userForm= response.data.user;
// this.userForm.email = response.data.user.email;
})
},
updateProfile () {
axios.put('/update-profile',
{
name: this.userForm.name,
email: this.userForm.email,
})
.then(response => {
this.userForm.name = response.data.name;
this.userForm.email = response.data.email;
swal({
icon: "success",
text: "Update Succesfully!",
});
})
}
}
}
</script>
controller:
<?php
namespace App\Http\Controllers;
use JWTAuth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\DB;
use Tymon\JWTAuth\Facades\JWTAuth as FacadesJWTAuth;
use App\Http\Requests\Users\UpdateProfileRequest;
class AuthController extends Controller
{
public $token = true;
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(),
[
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error'=>$validator->errors()], 401);
}
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->token) {
return $this->login($request);
}
return response()->json([
'success' => true,
'data' => $user
], Response::HTTP_OK);
}
public function login(Request $request)
{
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'success' => false,
'message' => 'Invalid Email or Password',
], Response::HTTP_UNAUTHORIZED);
}
// return response()->json([
// 'success' => true,
// 'token' => $jwt_token,
// ]);
return $this->respondWithToken($jwt_token);
}
public function logout(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'success' => true,
'message' => 'User logged out successfully'
]);
} catch (JWTException $exception) {
return response()->json([
'success' => false,
'message' => 'Sorry, the user cannot be logged out'
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
//update user profile
// public function updateProfile(UpdateProfileRequest $request)
// {
// $user = Auth::user();
// $jwt_token = auth('api')->tokenById($user->id);
// $input = $request->all();
// if ($jwt_token) {
// // $user = Auth::user();
// // $users = $user->user;
// $user->name = $request->input('name', '');
// $user->email = $request->input('email', '');
// $user->save();
// }
// // $user->update($request->all());
// // return ['message' => 'Updated the user info'];
// return $this->respondWithToken($jwt_token);
// }
public function updateProfile(UpdateProfileRequest $request)
{
DB::transaction(function() use ($request){
$user = Auth::user();
$user->name = $request->input('name','');
$user->email = $request->input('email','');
$user->save();
});
// $user->update([
// 'name' => $request->name,
// 'email' => $request->email,
// ]);
return ['message' => 'Updated the user info sucessfully!'];
}
public function userProfile()
{
// return response()->json(auth()->user());
$user = auth('api')->user();
$token = auth('api')->tokenById($user->id);
return response([
'user' => $user,
'token' => $token
]);
// return $this->respondWithToken($token);
}
public function getUser(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}
// Refresh a token.
public function refresh()
{
return $this->respondWithToken(JWTAuth::refresh());
}
// Get the token array structure
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'user' => $this->guard()->user(),
'token_type' => 'bearer',
'expires_in' => JWTAuth::factory()->getTTL() * 60
]);
}
public function guard() {
return Auth::Guard('api');
}
}
routes:
Route::put('/update-profile', [AuthController::class, 'updateProfile']);
store.js
import {getLoggedinUser} from './auth';
const user = getLoggedinUser();
export default {
state: {
currentUser: user,
isLoggedin: !!user,
loading: false,
auth_error: null,
reg_error:null,
registeredUser: null,
update: null,
},
getters: {
isLoading(state){
return state.loading;
},
isLoggedin(state){
return state.isLoggedin;
},
currentUser(state){
return state.currentUser;
},
authError(state){
return state.auth_error;
},
regError(state){
return state.reg_error;
},
registeredUser(state){
return state.registeredUser;
},
update(state){
return state.update;
}
},
mutations: {
login(state){
state.loading = true;
state.auth_error = null;
},
loginSuccess(state, payload){
state.auth_error = null;
state.isLoggedin = true;
state.loading = false;
state.currentUser = Object.assign({}, payload.user , {token: payload.access_token});
localStorage.setItem("user", JSON.stringify(state.currentUser));
},
loginFailed(state, payload){
state.loading = false;
state.auth_error = payload.error;
},
logout(state){
localStorage.removeItem("user");
state.isLoggedin = false;
state.currentUser = null;
},
registerSuccess(state, payload){
state.reg_error = null;
state.registeredUser = payload.user;
},
registerFailed(state, payload){
state.reg_error = payload.error;
},
// update(state, payload) {
// state.currentUser = payload.data;
// }
},
actions: {
login(context){
context.commit("login");
},
// updateUser(context) {
// const token = localStorage.getItem('token')
// axios.put('/api/auth/update-profile', {
// headers:
// {
// Authorization: `Bearer ${token}`
// }
// })
// .then((response) => {
// context.commit('update', response.data);
// })
// }
}
};
auth.js
import { setAuthorization } from "./general";
export function registerUser(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/register', credentials)
.then(response => {
res(response.data);
})
.catch(err => {
rej('An error occured.. try again later.')
})
})
}
export function login(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/login', credentials)
.then(response => {
// setAuthorization(response.data.access_token);
res(response.data);
})
.catch(err => {
rej('Wrong Email/Password combination.')
})
})
}
export function getLoggedinUser(){
const userStr = localStorage.getItem('user');
if(!userStr){
return null
}
return JSON.parse(userStr);
}
The login and register function are working well just the profile cannot be updated. Please help me if you have any solution or ideas.
For update profile method, Bearer token need to pass to axios request as well.
updateProfile () {
const token = this.$store.getters.currentUser.token // get the token from state
axios.put('/update-profile',
{
name: this.userForm.name,
email: this.userForm.email,
},
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json" // add content-type
}
})
.then(response => {
this.userForm.name = response.data.name;
this.userForm.email = response.data.email;
swal({
icon: "success",
text: "Update Succesfully!",
});
})
}
P.S. If you want axios to include Bearer token in all requests at all time without specify it on each request, you can axios.defaults.headers but it is another topic
the result of the console.log(this.$store.getters.currentUser.token)
I can get the token
and this is the localStorage
even here I also get the token in the error
PUT error
error
And here is the postman authorization that I put
Postman
the body part in postman

Live Search Component

I am fetching my data from external API link and I would like to filter them - live searching, so when I type a letter, the results that includes that letter will get filtered.
For now I am not able to do it and when I click into my input I just get all the results printed out and nothing is happening when I am trying to filter them.
This is my logic in script:
data() {
return {
result: "",
modal: false,
results: [],
filteredResults: [],
};
},
mounted() {
axios
.get("secretDataURL")
.then((response) => {
this.filteredResults = response.data;
})
.catch((error) => (this.filteredResults = console.log(error)))
.finally(() => console.log("Data successfully loaded"));
},
methods: {
filterResults() {
if (this.result.lenght == 0) {
this.filteredResults = this.results;
}
this.filteredResults = this.results.filter((result) => {
return result.toLowerCase().startsWith(this.result.toLowerCase());
});
},
setResult(result) {
this.result = result;
this.modal = false;
},
},
watch: {
state() {
this.filterResults();
},
}
And my template
<div #click="modal = false"></div>
<input
type="text"
v-model="result"
autocomplete="off"
#input="filterResults"
#focus="modal = true"
/>
<div v-if="filteredResults && modal">
<ul>
<li
v-for="(filteredResult, index) in filteredResults"
:key="index"
#click="setResult(filteredResult)"
>
{{ filteredResult.name }}
</li>
</ul>
</div>
How can I make it work, where my logic is failing ?
U get the data in hook mounted.
And then lost it.
Change this.filteredResults = response.data; to this.results = response.data;

Quasar upload file from axios

I have a form with multiple inputs that includes file input too. Now, I want to pass these data on the onSubmit function. but, there is an issue, in the quasar documentation, I didn't see instruction about file upload by Axios in the script part.
I read Uploader in the quasar doc and also I read this one from Stackoverlow, But I didn't work for me.
Also, this is my templates code:
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
#submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
#add="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
And the methods part:
file_selected: function (file) {
console.log(file)
this.selected_file = file[0]
this.check_if_document_upload = true
},
onSubmit: function () {
const url = '/core/v1/api/songs/upload'
const fileData = new FormData()
fileData.append('file_data', this.selected_file)
fileData.append('song_id', this.song_id)
this.$axios.post(url, fileData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(function () {
console.log('SUCCESS!!')
})
.catch(function () {
console.log('FAILURE!!')
})
And data part:
data: () => ({
selected_file: '',
check_if_document_upload: false,
song_id: '',
song_data: {
status: true
},
dashData: []
}),
If quasar uploads isn't working for you and you are using state management vuex, you could attempt writing custom code to accomplish what you want. Try this for sending the post request using axios
createEvents({ commit }, payload) {
const stuff = {
title: payload.title,
location: payload.location,
description: payload.description,
image = payload.image;
};
let formData = new FormData();
bodyFormData.set('title', stuff.title); //done for the text data
formData.append("imageUrl", stuff.image); //done for file data
axios
.post({
method: 'post',
url: 'myurl',
data: formData,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(response => {
commit("createEvents", response.data);
})
.catch(err => err.data);
}
}
And for the submit function(method), it should look something like this
createEvent(){
const newEvent = {
title: '',
location: '',
description: '',
image: this.image,
};
this.$store.dispatch("createEvents", newEvent);
};
finally, the form itself in your code. The image should be referenced with a simple
<input type='file' ref='image'> and the rest of your form can be normal
<form>
<input type='text' v-model='text'>
<-- more of the same -->
<input type='file' ref='image'>
// prevent is to keep the page from reloading when the form gets submitted,
// just a precaution measure
<button type=submit #click.prevent=createEvent()>submit</button>
</form>
Hope this helped
I found my issue. I should change #add to #added in the template.
<template>
<div class="q-pa-md q-mt-md">
<q-card class="my-card">
<q-form
#submit="onSubmit"
class="q-gutter-md"
>
<div class="row justify-center">
<q-uploader
label="Upload your music"
color="purple"
accept=".mp3"
:max-file-size="20000000"
square
flat
#added="file_selected"
bordered
/>
</div>
<div class="row justify-center">
<q-btn label="Edit" type="submit" color="primary" v-if="song_id" class="q-ma-md" />
<q-btn label="Add" type="submit" color="primary" v-else class="q-ma-md" />
<q-btn label="Cancel" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</q-card>
</div>
</template>
If you want to keep the QUploader functionalities, status changes, upload progress, in my case I made the component extension and it works fine, maybe it is not efficient because I had to add my own methods: upload, __uploadFiles.
Don't add method to override __runFactory, since I omitted batch load option, and I will always use factory as function.
QUploader source:
Part Code from Quasar Components Uploader -> xhr mixin.js
upload () {
if (this.canUpload === false) {
return
}
const queue = this.queuedFiles.slice(0)
this.queuedFiles = []
if (this.xhrProps.batch(queue)) {
this.__runFactory(queue)
}
else {
queue.forEach(file => {
this.__runFactory([ file ])
})
}
},
__runFactory (files) {
this.workingThreads++
if (typeof this.factory !== 'function') {
this.__uploadFiles(files, {})
return
}
const res = this.factory(files)
if (!res) {
this.$emit(
'factory-failed',
new Error('QUploader: factory() does not return properly'),
files
)
this.workingThreads--
}
else if (typeof res.catch === 'function' && typeof res.then === 'function') {
this.promises.push(res)
const failed = err => {
if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
if (this.promises.length === 0) {
this.abortPromises = false
}
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('factory-failed', err, files)
this.workingThreads--
}
}
res.then(factory => {
if (this.abortPromises === true) {
failed(new Error('Aborted'))
}
else if (this._isBeingDestroyed !== true && this._isDestroyed !== true) {
this.promises = this.promises.filter(p => p !== res)
this.__uploadFiles(files, factory)
}
}).catch(failed)
}
else {
this.__uploadFiles(files, res || {})
}
},
__uploadFiles (files, factory) {
const
form = new FormData(),
xhr = new XMLHttpRequest()
const getProp = (name, arg) => {
return factory[name] !== void 0
? getFn(factory[name])(arg)
: this.xhrProps[name](arg)
}
const url = getProp('url', files)
if (!url) {
console.error('q-uploader: invalid or no URL specified')
this.workingThreads--
return
}
const fields = getProp('formFields', files)
fields !== void 0 && fields.forEach(field => {
form.append(field.name, field.value)
})
let
uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted
xhr.upload.addEventListener('progress', e => {
if (aborted === true) { return }
const loaded = Math.min(maxUploadSize, e.loaded)
this.uploadedSize += loaded - uploadedSize
uploadedSize = loaded
let size = uploadedSize - uploadIndexSize
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const
file = files[i],
uploaded = size > file.size
if (uploaded) {
size -= file.size
uploadIndex++
uploadIndexSize += file.size
this.__updateFile(file, 'uploading', file.size)
}
else {
this.__updateFile(file, 'uploading', size)
return
}
}
}, false)
xhr.onreadystatechange = () => {
if (xhr.readyState < 4) {
return
}
if (xhr.status && xhr.status < 400) {
this.uploadedFiles = this.uploadedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'uploaded') })
this.$emit('uploaded', { files, xhr })
}
else {
aborted = true
this.uploadedSize -= uploadedSize
this.queuedFiles = this.queuedFiles.concat(files)
files.forEach(f => { this.__updateFile(f, 'failed') })
this.$emit('failed', { files, xhr })
}
this.workingThreads--
this.xhrs = this.xhrs.filter(x => x !== xhr)
}
xhr.open(
getProp('method', files),
url
)
if (getProp('withCredentials', files) === true) {
xhr.withCredentials = true
}
const headers = getProp('headers', files)
headers !== void 0 && headers.forEach(head => {
xhr.setRequestHeader(head.name, head.value)
})
const sendRaw = getProp('sendRaw', files)
files.forEach(file => {
this.__updateFile(file, 'uploading', 0)
if (sendRaw !== true) {
form.append(getProp('fieldName', file), file, file.name)
}
file.xhr = xhr
file.__abort = () => { xhr.abort() }
maxUploadSize += file.size
})
this.$emit('uploading', { files, xhr })
this.xhrs.push(xhr)
if (sendRaw === true) {
xhr.send(new Blob(files))
}
else {
xhr.send(form)
}
}
Result: With AXIOS - Component Vue that extend from QUploader
<script lang="ts">
import { QUploader } from 'quasar';
export default class AxiosUploader extends QUploader {
constructor(props) {
super(props);
}
AxiosUpload() {
if (this.canUpload === false) {
return;
}
const queue = this.queuedFiles.slice(0);
this.queuedFiles = [];
const factory = this.factory(queue);
queue.forEach(file => {
this.workingThreads++;
this.uploadFiles([file], factory);
});
}
uploadFiles(files, factory) {
const form = new FormData(),
headers = {};
factory.headers.forEach(head => {
headers[head.name] = head.value;
});
factory.formFields.forEach(field => {
form.append(field.name, field.value);
});
form.append(factory.fieldName, files[0], files[0].name);
let uploadIndex = 0,
uploadIndexSize = 0,
uploadedSize = 0,
maxUploadSize = 0,
aborted;
const xhr = this.$axios.post(factory.url, form, {
headers,
onUploadProgress: (e: ProgressEvent) => {
if (aborted === true) {
return;
}
const loaded = Math.min(maxUploadSize, e.loaded);
this.uploadedSize += loaded - uploadedSize;
uploadedSize = loaded;
let size = uploadedSize - uploadIndexSize;
for (let i = uploadIndex; size > 0 && i < files.length; i++) {
const file = files[i],
uploaded = size > file.size;
if (uploaded) {
size -= file.size;
uploadIndex++;
uploadIndexSize += file.size;
this.__updateFile(file, 'uploading', file.size);
} else {
this.__updateFile(file, 'uploading', size);
return;
}
}
}
});
this.xhrs.push(xhr);
this.$emit('uploading', { files, xhr });
xhr
.then(res => {
this.uploadedFiles = this.uploadedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'uploaded');
});
this.$emit('uploaded', { files, xhr });
})
.catch(err => {
aborted = true;
this.uploadedSize -= uploadedSize;
this.queuedFiles = this.queuedFiles.concat(files);
files.forEach(f => {
this.__updateFile(f, 'failed');
});
this.$emit('failed', { files, xhr });
})
.finally(() => {
this.workingThreads--;
this.xhrs = this.xhrs.filter(x => x !== xhr);
});
files.forEach(file => {
this.__updateFile(file, 'uploading', 0);
file.xhr = xhr;
file.__abort = () => {
xhr.abort();
};
maxUploadSize += file.size;
});
this.$emit('uploading', { files, xhr });
this.xhrs.push(xhr);
}
}
</script>
The component to use is AxiosUploader instead of q-uploader,
and instead of calling the upload () method, I call the AxiosUpload method. You could adapt to your needs

Vue-Apollo and query autocomplete

I'm new to Vue and i'm trying now to do a query update on q-autocomplete component (i have to use Quasar Framework).
This is the FormAdmin component:
<template>
<q-form #submit="submit" #reset="onReset" class="q-gutter-md">
<q-select
filled
v-model="form.UserId"
label="User Email"
use-input
hide-selected
fill-input
input-debounce="0"
:options="options"
#filter="filterFn"
hint="Mininum 2 characters to trigger autocomplete"
style="width: 250px; padding-bottom: 32px"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No results
</q-item-section>
</q-item>
</template>
</q-select>
<div>
<q-btn label="Submit" type="submit" color="primary"/>
<q-btn label="Reset" type="reset" color="primary" flat class="q-ml-sm" />
</div>
</q-form>
</template>
This is the basic code for the update function into the filterFn:
<script>
export default {
data () {
return {
model: null,
options: null,
}
},
props: ['form', 'submit'],
methods: {
filterFn (val, update, abort) {
if (val.length < 3) {
abort()
return
}
update(() => {
console.log(val);
})
},
onReset(){
},
}
}
</script>
I tried this code:
<script>
import gql from 'graphql-tag';
const stringOptions = gql`
query {
filterUsersListFirst {
UserEmail
}
}`
export default {
data () {
return {
model: null,
options: Object.values(stringOptions),
}
},
props: ['form', 'submit'],
methods: {
filterFn (val, update, abort) {
if (val.length < 3) {
abort()
return
}
this.$apollo.query({
query: gql`query($email: String!) {
filterUsersListByEmail(
email: $email
) {
UserEmail
}
}`,
variables: {
email: val,
}
}).then(data => {
console.log(JSON.stringyfy(data));
this.options = Object.values(data);
}).catch(error =>{
console.log({error});
});
},
onReset(){
},
}
}
</script>
I tried graphql query server-side and it works.
Also i tried to print data that the Promise returns and it results in:
{"data":{"filterUsersListByEmail":[{"UserEmail":"email1","__typename":"User"},{...}]},"loading":false,"networkStatus":7,"stale":false}
But i don't know how to append the query result in the q-select options.
I found myself the solution and i'll write it:
methods: {
filterFn (val, update, abort) {
if (val.length < 3) {
abort()
return
}
setTimeout(() => {
update(() => {
this.$apollo.query({
query: gql`query($email: String!) {
filterUsersListByEmail(
email: $email
) {
UserId
UserEmail
}
}`,
variables: {
email: val,
}
}).then(data => {
var emailList = [];
for(var i = 0; i < data.data.filterUsersListByEmail.length; i++)
{
emailList[i] = JSON.parse('{"label":"' + data.data.filterUsersListByEmail[i].UserEmail + '", "value":"' + data.data.filterUsersListByEmail[i].UserId + '"}');
}
this.options = usersList;
}).catch(error =>{
console.log({error});
});
})
}, 1000)
},
onReset(){
...
},
}

Function only gets called once in NuxtJs

I am using NuxtJs in my project, I a have list of checkboxes, on click of each checkbox I am sending an array of checkboxes to a my POST api which return data.
Here, when I check the first checkbox it returns the data. But when I check the second checkbox it does not does return the data.
I mean it only returns the data on single checkbox checked.
Its working with normal vuejs but not in nuxtjs
My Code:
<script>
import axios from "axios";
import uniq from "lodash/uniq";
export default {
async asyncData({ req, params }) {
let [storeInfo, feedsInfo] = await Promise.all([
axios.get(
process.env.apiURL +
"/stores/findOne?filter[where][store_name]" +
"=" +
params.id
),
axios.post(process.env.apiURL + "feeds/feedsByStores", {
stores: [params.id]
})
]);
return {
stores: storeInfo.data,
feeds: feedsInfo.data,
categories: uniq(feedsInfo.data.map(p => p.feed_category))
};
},
data() {
return {
checkedCategories: [],
checkedCategory: false,
selectedCategories: []
};
},
methods: {
feedsByCategories: function(categories) {
console.log(categories);
axios.post(process.env.apiURL + "feeds/feedsByCategories", {
categories: [categories]
}).then((res) => {
console.log(res);
})
},
categoryChecked: function(category, checked) {
this.display = "inline";
if (checked) {
this.selectedCategories.push(category);
console.log(this.selectedCategories);
this.feedsByCategories(this.selectedCategories);
} else if (!checked) {
const index = this.selectedCategories.indexOf(category);
this.selectedCategories.splice(index, 1);
this.feedsByCategories(this.selectedCategories);
if (this.selectedCategories == "") {
this.display = "none";
this.getFeeds();
}
}
if (!checked && this.selectedCategories.length === 0) {
this.getFeeds();
}
},
uncheckCategory: function(checkedCategory) {
this.checkedCategories = this.checkedCategories.filter(
name => name !== checkedCategory
);
const index = this.selectedCategories.indexOf(checkedCategory);
this.selectedCategories.splice(index, 1);
this.feedsByCategories(this.selectedCategories);
if (this.checkedCategories == "") {
this.display = "none";
this.getFeeds();
}
},
uncheckallCategories: function(event) {
this.checkedCategories = [];
this.display = "none";
this.search = "";
this.Search = "";
this.filteredCategories;
},
getFeeds() {
return this.feeds;
}
}
};
</script>
<template>
<v-layout>
<ul class="list-unstyled scrollbar">
<li v-for="(feedcategory, index) in categories" :key="feedcategory.id">
<input type="checkbox" name="category" #change="categoryChecked(feedcategory,$event.target.checked)"
:id="index + 1" :value="feedcategory" v-model="checkedCategories">
{{ feedcategory }}
</li>
</ul>
</v-layout>
</template>
My Typo,
I removed the brackets for my categories array and it worked:
feedsByCategories: function(categories) {
console.log(categories);
axios.post(process.env.apiURL + "feeds/feedsByCategories", {
categories: categories
}).then((res) => {
console.log(res);
})
}