Template reference property is missing - angular12

I am converting my angular 11 project to angular 12 and there are some problem I am facing. In one component which is ngx-nestable its working fine in angular 11 but as I have updated it to version 12 it's showing me some error please check screen shot.
This is my .ts file code:
import { Component, OnInit, ElementRef, Renderer2 } from '#angular/core';
import { NestableSettings } from './lib/nestable.models';
#Component({
selector: 'app-nestable',
templateUrl: './nestable.component.html',
styleUrls: ['./nestable.component.css']
})
export class NestableComponent implements OnInit {
public idCount = 13;
public options = {
fixedDepth: false
} as NestableSettings;
public list = [
{ 'id': 1 },
{
'expanded': true,
'id': 2, 'children': [
{ 'id': 3 },
{ 'id': 4 },
{
'expanded': false,
'id': 5, 'children': [
{ 'id': 6 },
{ 'id': 7 },
{ 'id': 8 }
]
},
{ 'id': 9 },
{ 'id': 10 }
]
},
{ 'id': 11 },
{
'id': 12,
'children': [
{ 'id': 13 }
]
},
{ 'id': 14 },
{ 'id': 15 }
];
constructor(
private el: ElementRef,
private renderer: Renderer2
) {
this.renderer.listen(this.el.nativeElement, 'listUpdated', e => {
this.list = e.detail.list;
});
}
public pushItem() {
this.list.push({ id: ++this.idCount });
this.list = [...this.list];
}
public toggleFixedDepth() {
this.options.fixedDepth = !this.options.fixedDepth;
}
public drag(e: any) {
console.log(e);
}
public drop(e: any) {
console.log(e);
}
public onDisclosure(e: any) {
console.log(e);
}
ngOnInit(): void {
}
}
and this is my html code
<ngx-nestable class="ngx-nestable col-lg-6"
(drag)="drag($event)"
(drop)="drop($event)"
(disclosure)="onDisclosure($event)"
[(list)]="list"
#nestable
[options]="options"
[template]="itemTemplate"
fxFlex="50">
</ngx-nestable>
<ng-template #itemTemplate let-row>
<button mat-icon-button [ngxNestableDragHandle]="row">
<mat-icon>drag_handle</mat-icon>
</button>
<button mat-icon-button *ngIf="row.item.children && row.item.children.length; else empty_item" [ngxNestableExpandCollapse]="row">
<mat-icon>{{row.item.$$expanded ? 'keyboard_arrow_down' : 'keyboard_arrow_right'}}</mat-icon>
</button>
<div>Item: {{row.item.id}}</div>
</ng-template>
Please tell me what should I change or add in the code file so that it will start working. I am trying to find a solution for many days but to no avail.
Thanks

This problem is resolved by just adding the below code in template file check screenshot
Thanks

Related

How to display data from firebase in vis.js timeline

I m using vis.js timeline and i want display date from firestore. It works when I type manually (look --> this.items), but does not work with firestore (look --> this.users).
I m using Vue framework.
<script>
export default {
data() {
return {
users: [],
items: [
{
id: '1',
content: 'London',
group: 'Mike',
start: '2021-12-20',
end: '2022-06-19',
},
],
}
},
async fetch() {
await this.loadPlaces()
},
methods: {
async loadPlaces() {
const querySnapshot = await getDocs(collection(db, 'places'))
querySnapshot.forEach((doc) => {
this.users.push({ id: doc.id, ...doc.data() })
})
this.$store.commit('places/setPlaces', this.users)
},
},
computed: {
places() {
return this.$store.state.places.places
},
},
mounted() {
let container = document.getElementById('visualization')
let options = {
moveable: true,
}
let timeline = new vis.Timeline(container)
timeline.setOptions(options)
timeline.setGroups(this.groups)
timeline.setItems(this.items)
},
}
</script>
I found a solution.
I just moved all code from mounted() to method loadPlaces (under this.$store.commit)
Save yourself trouble and use the vis datasets instead.
my pinia store in vue 3 looks like this.
import { defineStore } from 'pinia'
import { DataSet } from 'vis-data/esnext'
export const useVisData = defineStore('visData', {
state: () => ({
items: new DataSet([]),
groups: new DataSet([]),
selectedItems: [],
serializedGroupsAndItems: []
}),
actions: {
//Group actions
showAllGroups() {
this.groups.forEach(group => {
this.groups.updateOnly({ id: group.id, visible: true })
});
},
addGroup(group) {
this.groups.add(group)
},
hideGroup(group) {
this.groups.updateOnly({ id: group, visible: false })
},
//Item actions
addItem(item) {
this.items.add(item)
},
removeItem(item) {
this.items.remove(item)
},
setSelectedItems(items) {
this.selectedItems = items
},
//data add/remove
serializeData() {
this.serializedGroupsAndItems.push({
groups: JSON.stringify(this.groups.get()),
items: JSON.stringify(this.items.get())
})
},
loadSerializedData() {
this.clearGroupsAndItems()
this.serializedGroupsAndItems.forEach(data => {
this.addGroup(JSON.parse([data.groups]))
this.addItem(JSON.parse([data.items]))
})
},
//misc
clearGroupsAndItems() {
this.groups.clear()
this.items.clear()
}
},
getters: {
getHiddenGroups(state) {
return state.groups.get({
filter: (item) => {
return item.visible === false
}
})
}
}
})
Also remember to watch for changes in your options.
Might be better to wrap it in a vue component too. something like this.
this is what i did.
let timeline;
const visref = ref(null);
onMounted(async () => {
timeline = new Timeline(visref.value, props.items, props.groups, {...props.options, ...timelineOptions});
props.events.forEach(event => {
on(event, (properties) => {
// console.log(event, properties)
emits(`vis${event}`, properties);
});
});
})
<template>
<div ref="visref"></div>
</template>
then you can use it like so:
const timelineref = ref();
<Timeline
ref="timelineref"
:items="visStore.items"
:groups="visStore.groups"
:options="options"
/>
remember to expose the instance in your timeline component then you can call the functions using a ref like this.
timelineref.value.timeline.zoomOut(0.5)

Vuex, Vuexfire: How to get data from firestore into frontend?

I have some data in a firestore and want to display it in my vue app.
Firestore:
Test.vue
<template>
<p>{{ items }}</p>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: mapState(["items"]),
methods: {
getItems() {
this.$store.dispatch("bindItems");
},
},
mounted() {
this.getItems();
},
};
</script>
index.js
import { createStore } from "vuex";
import { firestoreAction } from "vuexfire";
import { vuexfireMutations } from "vuexfire";
import { db } from "./db";
const store = createStore({
state() {
return {
items: [],
};
},
actions: {
bindItems: firestoreAction(({ bindFirestoreRef }) => {
return bindFirestoreRef("items", db.collection("items"));
}),
},
mutations: {
...vuexfireMutations,
},
getters: {
items(state) {
return state.items;
},
},
});
store.subscribe((state) => console.log(state));
export default store;
To check my store, I added this line in index.js: store.subscribe((state) => console.log(state));. As it turns out, the data from firestore actually makes it to my store:
Why is it not rendered in the frontend? What do I have to change to make it appear?
Edit.
When I hardcode some data in my store and remove this.$store.dispatch("bisndItems"); from the monuted hook, the data gets rendered:
state() {
return {
items: {"name": "peter"},
};
},

Setting Firebase data to property in html file

Okay so i am fairly new at ionic and i am experiencing this problem where by i am getting the users data from firebase but whenever i set it to the public variable and try and reference it in the html file, i am getting a log error of "cannot set 'variable name' to property of undefined". Here is my code for a more clearer explanation and understanding of what i am trying to achieve. Thank you.
.ts file:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams,AlertController,
LoadingController, Loading } from 'ionic-angular';
import {AngularFireAuth} from 'angularfire2/auth';
import { MenuPage } from '../menu/menu';
import firebase from 'firebase';
import { first } from 'rxjs/operators';
#IonicPage()
#Component({
selector: 'page-account',
templateUrl: 'account.html',
})
export class AccountPage {
public userinfo;
constructor(public navCtrl: NavController, public navParams: NavParams,
private alertCtrl:AlertController, public fAuth:AngularFireAuth,
public loading:LoadingController) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad AccountPage');
this.readData();
}
isLoggedIn(){
return this.fAuth.authState.pipe(first()).toPromise();
}
userStatus(){
const user = this.isLoggedIn()
if(user){
console.log('logged in');
this.readData();
}else{
}
}
async readData(){
let load = this.loading.create({
content: "Setting up your profile...",
spinner:'dots'
});
load.present();
await this.fAuth.authState.subscribe((user:firebase.User) =>{
if(user){
firebase.database().ref('/users/' +
user.uid).once('value').then(function(snapshot){
if(snapshot.exists()){
var data = (snapshot.val() && snapshot.val().username) ||
'Anonymous';
//this.userinfo = data;
console.log(data);
}else{
console.log("i need a name");
}});
}else{
console.log("not logged in, log in please");
this.alertLogin();
};
});
console.log(this.userinfo );
load.dismiss();
}
getName(){
let alert = this.alertCtrl.create({
title: 'Hello new friend! :) please can you tell us your name...',
inputs: [
{
name: 'name',
placeholder: 'name'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Confirm',
handler: data => {
this.fAuth.authState.subscribe((user:firebase.User) =>{
firebase.database().ref('/users/' + user.uid).set({
username:data.name
});
});
}
}
]
});
alert.present();
}
alertLogin(){
//if user is not already logged in
let alert = this.alertCtrl.create({
title: 'Whoa there Sally! you need to log in first! :)',
inputs: [
{
name: 'email',
placeholder: 'email'
},
{
name: 'password',
placeholder: 'Password',
type: 'password'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
handler: data => {
console.log('Cancel clicked');
this.navCtrl.setRoot(MenuPage);
}
},
{
text: 'Login',
handler: data => {
this.login(data.email,data.password);
}
},{
text: 'Register',
handler: data => {
this.register(data.email,data.password);
}
}
]
});
alert.present();
}
async login(email,password){
try{
var login = await this.fAuth.auth.signInWithEmailAndPassword(
email,
password
);
if(login){
console.log("Successfully logged in!");
}
}catch(err){
console.error(err);
alert("Sorry we couldnt find you in our system :(");
this.navCtrl.setRoot(MenuPage);
}
}
async register(email,password){
try{
var reg = await this.fAuth.auth.createUserWithEmailAndPassword(
email,
password
);
if(reg){
this.getName();
console.log("successfully registered!");
this.navCtrl.setRoot(AccountPage);
}
}catch(err){
console.error(err);
}
}
logout(){
this.fAuth.auth.signOut();
}
}
.html file:
<ion-item>
<h1>{{userinfo}}</h1>
</ion-item>
Okay so i have tried basically everything and have decided to rather just upload the name to the database and write it locally in the storage of the application. I will just pull the name, along with further details later on in the application process. However if anyone finds an answer for this post, i would greatly appreciate it!

Vue Component: how to pass data from parent to child

how can i access the doctor attribute from my doctor component ?
Vue.component('specialists', {
template: `
<div>
<div class="list-group-item title">
» {{ name }}
</div>
<doctor class="list-group-item" v-for="doctor in doctors">
<a href="#" class="list-group-item-heading">
{{ doctor.full_name }}
</a>
</doctor>
</div>
`,
props: {
name: {
default: '',
},
},
data: function() {
return {
algoliaClient: null,
algoliaIndex: null,
doctors: [],
};
},
created: function() {
this.algoliaClient = this.$parent.algoliaClient;
this.algoliaIndex = this.algoliaClient.initIndex('medical_doctors');
},
mounted: function() {
this.getDoctors();
},
methods: {
getDoctors: function() {
this.search(this.name);
},
search: function(input) {
var _this = this;
this.algoliaIndex.search(this.name, function(err, hits) {
_this.setDoctors(hits.hits);
});
},
setDoctors: function(data) {
this.doctors = data;
},
},
});
// my doctor component
Vue.component('doctor', {
template: `
<div><slot></slot></div>
`,
data: function() {
return {
doctor: null, // here. how can i pass value to it?
};
},
});
How can i access the doctor attribute from my specialists component ?
I've tried accessing the this.$children from specialists component but the child is null
I'd try something like this :
Vue.component('specialists', {
template: `
<div>
<div class="list-group-item title">
» {{ name }}
</div>
<doctor class="list-group-item" v-for="doctor in doctors" :doctor="doctor">
<a href="#" class="list-group-item-heading">
{{ doctor.full_name }}
</a>
</doctor>
</div>
`,
props: {
name: {
default: '',
},
},
data: function() {
return {
algoliaClient: null,
algoliaIndex: null,
doctors: [],
};
},
created: function() {
this.algoliaClient = this.$parent.algoliaClient;
this.algoliaIndex = this.algoliaClient.initIndex('medical_doctors');
},
mounted: function() {
this.getDoctors();
},
methods: {
getDoctors: function() {
this.search(this.name);
},
search: function(input) {
var _this = this;
this.algoliaIndex.search(this.name, function(err, hits) {
_this.setDoctors(hits.hits);
});
},
setDoctors: function(data) {
this.doctors = data;
},
},
});
// my doctor component
Vue.component('doctor', {
template: `
<div><slot></slot></div>
`,
props: {
doctor: {
default: '',
}
}
});
passing :doctor="doctor" in the for loop of the parent
and adding doctor to props in the child component
props: {
doctor: {
default: '',
},
},

Vuex state change is not reactive

I am working with Vuex and Firebase Auth system.
I just want to store with Vuex the user object that i get from:
firebase.auth().getCurrentUser
so that every time it changes, it updates the views.
But i ve troubles with this.
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {
loggedIn: false,
data: null
}
},
getters: {
user(state){
return state.user
}
},
mutations: {
SET_LOGGED_IN(state, value) {
state.user.loggedIn = value;
},
SET_USER(state, data) {
state.user.data = data;
}
},
actions: {
fetchUser({ commit }, user) {
commit("SET_LOGGED_IN", user !== null);
if (user) {
commit("SET_USER", user);
} else {
commit("SET_USER", null);
}
}
}
});
Account.vue
<template>
<ion-item>
<ion-label #click="openModal()" position="stacked">Your name</ion-label>
{{user.data.displayName}}
</ion-item>
</template>
computed: {
// map `this.user` to `this.$store.getters.user`
...mapGetters({
user: "user"
})
},
methods: {
openModal() {
let us = this.$store.getters.user;
return this.$ionic.modalController
.create({
component: Modal,
componentProps: {
data: {
content: 'New Content',
},
propsData: {
pro: us.data.displayName
},
},
})
.then(m => m.present())
},
.
.
.
</script>
Modal.vue
<template>
<ion-app>
<h1>MODAL</h1>
<ion-input :value="prop" #input="prop = $event.target.value"></ion-input>
<ion-button #click="clos()">Save</ion-button>
</ion-app>
</template>
<script>
import firebase from "firebase";
export default {
props:['pro'],
data(){
return{
prop: this.pro
}
},
methods:{
clos(){
let vm = this;
let user = firebase.auth().currentUser;
window.console.log("updating",vm.prop)
user.updateProfile({
displayName: vm.prop
}).then(function(){
user = firebase.auth().currentUser;
vm.$store.dispatch("fetchUser",user);
}).catch(function(err){
window.console.log("err",err);
})
this.$ionic.modalController.dismiss();
}
}
}
</script>
I can see using Vue Dev Tools that when I dispatch the new user in Modal.vue
vm.$store.dispatch("fetchUser",user);
that the Vuex state is correctly updated, but the view in Account.vue is not.
But if I press the button 'commit this mutation' in the dev tools the view updates!
How can I fix this behavior?
try this solution:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {
loggedIn: false,
data: null
}
},
getters: {
user(state){
return state.user;
},
userData(state){
return state.user.data;
}
},
mutations: {
SET_LOGGED_IN(state, value) {
state.user.loggedIn = value;
},
SET_USER(state, data) {
state.user.data = data;
}
},
actions: {
fetchUser({ commit }, user) {
commit("SET_LOGGED_IN", user !== null);
if (user) {
commit("SET_USER", user);
} else {
commit("SET_USER", null);
}
}
}
});
Account.vue
<template>
<ion-item>
<ion-label #click="openModal()" position="stacked">Your name</ion-label>
{{user.displayName}}
</ion-item>
</template>
computed: {
// map `this.user` to `this.$store.getters.user`
...mapGetters({
user: "userData"
})
},
methods: {
openModal() {
let us = this.$store.getters.userData;
return this.$ionic.modalController
.create({
component: Modal,
componentProps: {
data: {
content: 'New Content',
},
propsData: {
pro: us.displayName
},
},
})
.then(m => m.present())
},
.
.
.
</script>
You can try this:
SET_USER(state, data) {
Vue.$set(state.user, 'data', data)
}

Resources