Implementing a Database - Cannot read property 'initializedRelationships' of undefined - Ember js - firebase

here is the adapter
In Ember Data, an Adapter determines how data is persisted to a backend data store. Things such as the backend host, URL format and headers used to talk to a REST API can all be configured in an adapter.
/* adapters/application.js */
import FirebaseAdapter from "emberfire/adapters/firebase";
export default FirebaseAdapter.extend({});
A Controller is routable object which receives a single property from the Route .. here is the controller
/* controllers/cars.js */
import Controller from "#ember/controller";
export default Controller.extend({
actions: {
deleteCar(id) {
this.get("store")
.findRecord("car", id, { reload: true })
.then(car => {
car.destroyRecord();
car.save();
//self.transitionToRoute("cars");
});
}
}
});
/* controllers/cars/edit.js */
import Controller from "#ember/controller";
export default Controller.extend({
actions: {
editCar: function(id) {
var self = this;
var make = this.get("model.make");
var model = this.get("model.model");
var year = this.get("model.year");
this.store.findRecord("car", id).then(function(car) {
car.set("make", make);
car.set("model", model);
car.set("year", year);
car.save();
self.transitionToRoute("cars");
});
}
}
});
/* controllers/cars/new.js */
import Controller from "#ember/controller";
export default Controller.extend({
actions: {
addCar: function() {
var self = this;
var rand = Math.floor(Math.random() * 10000 + 1);
var newCar = this.store.createRecord("car", {
id: rand,
make: this.get("carMake"),
model: this.get("carModel"),
year: this.get("carYear")
});
newCar.save();
self.transitionToRoute("cars");
}
}
});
In Ember Data, models are objects that represent the underlying data that your application presents to the user. Note that Ember Data models are a different concept than the model method on Routes, although they share the same name .. here is the model
/* models/cars.js */
import DS from "ember-data";
export default DS.Model.extend({
make: DS.attr("string"),
model: DS.attr("string"),
year: DS.attr("string")
});
In Ember, when we want to make a new page that can be visited using a URL, we need to generate a "route" using Ember CLI .. here is the routes
/* routes/cars.js */
import Route from "#ember/routing/route";
export default Route.extend({
model() {
return this.store.findAll("car", {
orderBy: "make"
});
}
});
/* routes/cars/edit.js */
import Route from '#ember/routing/route';
export default Route.extend({});
/* routes/cars/new.js */
import Route from "#ember/routing/route";
export default Route.extend({
model() {
return this.store.findAll("car");
}
});
/* routes/users.js*/
import Route from "#ember/routing/route";
import $ from "jquery";
export default Route.extend({
model: function() {
var url = "https://api.github.com/users";
return $.getJSON(url).then(function(data) {
return data.splice(0, 10);
});
}
});
The EmberRouter class manages the application state and URLs .. here is the router
/* router.js */
import EmberRouter from "#ember/routing/router";
import config from "./config/environment";
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route("cars", function() {
this.route("new");
this.route("edit", { path: "/edit/:car_id" });
});
this.route("users");
});
export default Router;
A template is used to create a standard layout across multiple pages. When you change a template, the pages that are based on that template automatically get changed. Templates provide standardization controls.
<!-- templates/users.hbs -->
<h1>Github Users</h1>
<ul>
{{#each model as |user|}}
<li>{{user.login}}</li>
{{/each}}
</ul>
<!-- templates/car.hbs -->
{{#link-to "cars.new"}}Create Car{{/link-to}}
<hr>
{{outlet}}
<h1>Cars</h1>
<ul>
{{#each model as |car|}}
<li>
{{car.year}} {{car.make}} {{car.model}} -
{{#link-to "cars.edit" car.id}}Edit{{/link-to}}
<button {{action "deleteCar" car.id}}>Delete</button>
</li>
{{/each}}
</ul>
<!-- templates/application.hbs -->
{{outlet}}
<!-- templates/cars/new.hbs -->
<form {{action "addCar" on="submit"}}>
<p>Make: {{input type="text" value=carMake}}</p>
<p>Model: {{input type="text" value=carModel}}</p>
<p>Year: {{input type="text" value=carYear}}</p>
<p>{{input type="submit" value="submit"}}</p>
</form>
<!-- templates/cars/edit.hbs -->
<form {{action "editCar" model.id on="submit"}}>
<p>Make: {{input type="text" value=model.make}}</p>
<p>Model: {{input type="text" value=model.model}}</p>
<p>Year: {{input type="text" value=model.year}}</p>
<p>{{input type="submit" value="Submit"}}</p>
</form>
run
Uncaught TypeError: Cannot read property 'initializedRelationships' of
undefined
https://i.stack.imgur.com/y7Ax0.png
here is my app drive link

The error disappears when I remove the findAll query inside model hook. Probably this would be an error with firebase config.
You missed entering the below config. Make sure you have all these variables inside your app/config/environment.js
var ENV = {
firebase: {
apiKey: "your-api-key",
authDomain: "YOUR-FIREBASE-APP.firebaseapp.com",
databaseURL: "https://YOUR-FIREBASE-APP.firebaseio.com",
projectId: "YOUR-FIREBASE-APP",
storageBucket: "YOUR-FIREBASE-APP.appspot.com",
messagingSenderId: "00000000000"
}
}
My app works fine with firebase. Please do follow the step by step approach from here
You have installed both stable and latest build versions of emberfire,
"emberfire": "^2.0.10",
"emberfire-exp": "^3.0.0-rc.1-4",
Which is not necessary. Install any one version.

if you are using ember-cli 3.12.0, when you are creating the firebase connection with your app by default "emberfire/adapters/firebase" will be imported automatical in adapters/application.js, which is not true.
`/* adapters/application.js */
import FirebaseAdapter from "emberfire/adapters/firebase";
export default FirebaseAdapter.extend({});`
go there and edit that import to "emberfire/adapters/firestore".
`import FirebaseAdapter from 'emberfire/adapters/firestore';
export default FirebaseAdapter.extend({
});`
and downgrade your "ember-source to : 3.10.0" in package.json

Related

trpc v10 - Error: Query data cannot be undefined

New to trpc. Trying to get basic query functionality but it's not working. Not sure what I'm missing. In v9 it used createReactQueryHooks(), but it seems in v10 you only need to use createTRPCNext() if I'm not mistaken inside util/trpc.tsx.
Error:
next-dev.js:32 Error: Query data cannot be undefined - affected query key: ["greeting"]
at Object.onSuccess (query.mjs:320:19)
at resolve (retryer.mjs:64:50)
// utils/trpc.ts
export const trpc = createTRPCNext<AppRouter, SSRContext>({
config({ ctx }) {
return {
transformer: superjson, // optional - adds superjson serialization
links: [
httpBatchLink({
/**
* If you want to use SSR, you need to use the server's full URL
* #link https://trpc.io/docs/ssr
**/
url: `${getBaseUrl()}/api/trpc`,
}),
],
/**
* #link https://react-query-v3.tanstack.com/reference/QueryClient
**/
// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
headers() {
if (ctx?.req) {
// To use SSR properly, you need to forward the client's headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
// If you're using Node 18, omit the "connection" header
const {
// eslint-disable-next-line #typescript-eslint/no-unused-vars
connection: _connection,
...headers
} = ctx.req.headers;
return {
...headers,
// Optional: inform server that it's an SSR request
"x-ssr": "1",
};
}
return {};
},
};
},
ssr: true,
});
// server/router/_app.ts
import { t } from '#/server/trpc';
import { userRouter } from '#/server/router/user';
import { postRouter } from '#/server/router/posts';
import { authRouter } from './authy';
export const appRouter = t.router({
user: userRouter,
post: postRouter,
authy: authRouter,
greeting: t.procedure.query(() => 'hello tRPC v10!'),
});
export type AppRouter = typeof appRouter;
// server/router/authy.ts
import { t } from "#/server/trpc";
import * as trpc from "#trpc/server";
import { z } from "zod";
export const authRouter = t.router({
hello: t.procedure
// using zod schema to validate and infer input values
.input(
z.object({
text: z.string().nullish(),
})
.nullish().optional()
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? "world"}`,
};
}),
});
export type AuthRouter = typeof authRouter;
None of the routes work. They all show a similar error.
// pages/test.tsx
import React from "react";
import { NextPage } from "next";
import { trpc } from "#/utils/trpc";
const TestPage: NextPage = () => {
const helloNoArgs = trpc.authy.hello.useQuery();
const helloWithArgs = trpc.authy.hello.useQuery({ text: "client" });
const greeting = trpc.greeting.useQuery();
return (
<div>
<h1>Hello World Example</h1>
<ul>
<li>
helloNoArgs ({helloNoArgs.status}):{" "}
<pre>{JSON.stringify(helloNoArgs.data, null, 2)}</pre>
</li>
<li>
helloWithArgs ({helloWithArgs.status}):{" "}
<pre>{JSON.stringify(helloWithArgs.data, null, 2)}</pre>
</li>
<li>
greeting ({greeting.status}):{" "}
<pre>{JSON.stringify(greeting.data, null, 2)}</pre>
</li>
</ul>
</div>
);
};
export default TestPage;
It seems you are using superjson. You need to add superjson transformer at initTRPC.
routers/router/_app.ts
import { initTRPC } from '#trpc/server';
import superjson from 'superjson';
export const t = initTRPC.create({
transformer: superjson,
});
more detailed instruction can be found here: TRPC v10
Omgosh... it was because I was using "^10.0.0-proxy-beta.7" and not "^10.0.0-proxy-beta.8"
Edit: Somehow I had another error and encountered my own question again 22 days later and solved it again. In general, when using trpc it seems updating to all the #next packages is best as it seems to be somewhat easy to have packages not talking to each other as they improve.
https://trpc.io/docs/v10/quickstart#installation-snippets
On my side I was using a mocked trpc server that was not using superjson (whereas the real one was). I just used superjson.serialize(...) before adding the JSON body to my response (in my server mock), then it worked :)

Vue3 Add html to existing project

I’ve built my first project and have run the build process. I have my index.html file and it works if opened directly.
I’ve copied the code into an existing html page and the initial page load is fine. However, when props get updated, binding (v-if statements) no longer works.
Any help would be great
Edit with code example
<script>
import { ref } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
export default {
components: {
'Determining': Determining,
'Ready': Ready,
},
setup() {
let checkout = ref({
state: 'determining',
});
return {
checkout,
};
},
created() {
this.checkout.state = 'ready';
console.log("I am getting here");
}
}
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>
The determining state is shown when the page first loads. The console log is firing in setup, but Ready component is not showing
Progress
I've narrowed it down to other javascript running on the page.
Any javascript, even just
<script>console.log("hello");</script>
Is enough to break it.
Other than adding additional javascript to Vue, is there anyway around it?
if I'm not wrong, you can't access composition api or setup() variables in options api (such as created, mounted, data, methods etc). You can use beforeMount as #Thomas commented or onMounted by importing it from vue, for the example:
<script>
import { ref, beforeCreate } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
export default {
components: {
'Determining': Determining,
'Ready': Ready,
},
setup() {
beforeCreate(()=> {
checkout.state.value = 'ready';
console.log("I am getting here");
})
let checkout = ref({
state: 'determining',
});
return {
checkout,
};
}
}
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>
if you want it more simple, you can use script sugar setup, this way you don't need to return in stup(). It can make your code simpler but if you want to define props, the approach is different
<script setup>
import { ref, beforeCreate } from "vue";
import Determining from './Determining.vue'
import Ready from './Ready.vue'
beforeCreate(()=> {
checkout.state.value = 'ready';
console.log("I am getting here");
})
let checkout = ref({
state: 'determining',
});
</script>
<template>
<Determining v-if="checkout.state == 'determining'" />
<Ready v-if="checkout.state == 'ready'" />
</template>

CodeMirror on Vue3 has a problem when setValue is kicked

I'm trying to use CodeMirror on Vue3 and the problem occurs when I call doc.setValue().
The Problem is following:
Cursor position is broken when doc.setValue() is called
CodeMirror throws an exception when continuing editing
The exception is here.
Uncaught TypeError: Cannot read property 'height' of undefined
at lineLength (codemirror.js:1653)
at codemirror.js:5459
at LeafChunk.iterN (codemirror.js:5623)
at Doc.iterN (codemirror.js:5725)
at Doc.iter (codemirror.js:6111)
at makeChangeSingleDocInEditor (codemirror.js:5458)
at makeChangeSingleDoc (codemirror.js:5428)
at makeChangeInner (codemirror.js:5297)
at makeChange (codemirror.js:5288)
at replaceRange (codemirror.js:5502)
How should I solve this?
~~~
Versions are CodeMirror: 5.61.1, Vue.js: 3.0.11
My code is following:
index.html
<div id="app"></div>
<script src="./index.js"></script>
index.js
import { createApp } from 'vue';
import App from './App';
const app = createApp(App);
app.mount('#app');
App.vue
<template>
<div>
<button #click="click">Push Me</button>
<textarea id="codemirror"></textarea>
</div>
</template>
<script>
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
this.cm.getDoc().setValue('foo\nbar');
}
}
}
</script>
Thanks.
UPDATES
First, this problem also occurs when I used replaceRange() with multiline.
Unfortunately, I couldn't find any solution. So I tried to find another way.
My solution is recreating Codemirror instance with a textarea that has new content.
It works well.
// Remove old editor
this.cm.toTextArea();
// Get textarea
const textarea = document.getElementById('codemirror');
// Set new content
textarea.value = 'foo\nbar';
// Create new editor
this.cm = CodeMirror.fromTextArea(textarea, { /** options */ });
I found a method, you can use toRaw to get the original Object from Proxy,and this method can be also used in monaco-editor
import { toRaw } from 'vue'
import CodeMirror from 'codemirror/lib/codemirror.js';
import 'codemirror/lib/codemirror.css';
// import codemirror resources
import 'codemirror/addon/mode/overlay.js';
import 'codemirror/mode/markdown/markdown.js';
import 'codemirror/mode/gfm/gfm.js';
export default {
data () {
return {
cm: null
}
},
mounted () {
this.cm = CodeMirror.fromTextArea(document.getElementById('codemirror'), {
mode: 'gfm',
lineNumbers: true,
});
},
methods: {
click (event) {
toRaw(this.cm).setValue('foo\nbar');
}
}
}
Another way,you don't have to define cm in data, just use this.cm
data () {
return {
//cm: null
}
},

Vue.js / Firebase and Vuefire - Read and update a single object

I've been trying to set up a simple app to test some Vue.js features and I've been finding here and there some intersting tutorials about basic CRUD implementation.
I've been stuck on something a little different since a few days, here's a simple description of what I try to achieve :
Set up a home page that displays first and last name.
Store first and last name in firebase as strings
Simply display the two strings on screen
later allow the logged-in user to edit the string (not part of my problem here but relevant to explain why I need the two fields to be stored in Firebase)
I've already worked on a small architecture with login management, different menus for logged in/out states, things like that.
So I already set up that in Firebase :
Firebase configuration
Then here my core files :
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase'
import VueFire from 'vuefire'
import { store } from './store/store'
let app
let config = {
apiKey: '######',
authDomain: '######',
databaseURL: '######',
projectId: '######',
storageBucket: '######',
messaginSenderId: '######'
}
firebase.initializeApp(config)
firebase.auth().onAuthStateChanged(function (user) {
if (!app) {
/* eslint-disable no-new */
app = new Vue({
el: '#app',
store: store,
router,
template: '<App/>',
components: { App }
})
}
})
export const db = firebase.database()
export const homeContent = db.ref('homeContent')
Vue.config.productionTip = false
Index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '#/components/HelloWorld'
import Test from '#/components/Test'
import Login from '#/components/Login'
import SignUp from '#/components/SignUp'
import firebase from 'firebase'
import VueFire from 'vuefire'
Vue.use(Router)
Vue.use(VueFire)
let router = new Router({
routes: [
{
path: '*',
redirect: '/login'
},
{
path: '/',
redirect: '/login'
},
{
path: '/login',
name: 'Login',
component: Login
},
{
path: '/test',
name: 'Test',
component: Test,
meta: {
requiresAuth: true
}
},
{
path: '/sign-up',
name: 'SignUp',
component: SignUp
},
{
path: '/hello-world',
name: 'HelloWorld',
component: HelloWorld,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach((to, from, next) => {
let currentUser = firebase.auth().currentUser
let requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth && !currentUser) next('/login')
else if (!requiresAuth && currentUser) next()
else next()
})
export default router
App.vue
<template>
<div id="app">
<div v-if="user">Logged in</div>
<div v-else>NOT logged in</div>
<Navigation></Navigation>
<button id="btLogout" v-if="user" v-on:click="logout">Déconnexion</button>
<img class="logo" src="./assets/logo.png">
<router-view/>
</div>
</template>
<script>
// Register Navbar component
import Navigation from './components/Nav.vue'
import firebase from 'firebase'
export default {
computed: {
user () {
return this.$store.getters.getUser
}
},
components: {
'Navigation': Navigation
},
methods: {
logout: function () {
firebase.auth().signOut().then(() => {
this.$store.dispatch('clearUser')
this.$router.replace('login')
})
},
setUser: function () {
this.$store.dispatch('setUser')
}
},
created () {
// when the app is created run the set user method
// this uses Vuex to check if a user is signed in
// check out mutations in the store.js file
this.setUser()
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.logo {
width: 50px;
height: auto;
clear: both;
display: block;
margin: 30px auto 0;
}
#btLogout {
clear: both;
display: inline-block;
}
</style>
Test.vue
<template>
<div class="homeScreen">
<p v-bind:key="homeContent['.key']" v-for="firstName of homeContent">{{ homeContent.firstName }}</p>
<p v-bind:key="homeContent['.key']" v-for="lastName of homeContent">{{ homeContent.lastName }}</p>
<img src="../assets/annonce_motw.jpg">
</div>
</template>
<!-- Javascript -->
<script>
import firebase from 'firebase'
import db from "../main"
export default {
data () {
return {
db: ''
}
},
firebase: {
homeContent: {
source: db.ref('homeContent'),
asObject: true
}
},
methods: {
setHomeName (key) {
// homeName.child(key).update({ edit: true })
}
},
created () {
}
}
</script>
<!-- SASS styling -->
<style scoped>
</style>
So here I am. The part where I'm stuck is that everytime I try to add in Test.vue the line db.ref('homeContent') the console returns that db is undefined.
I also can't figure how to simply output the stored strings after resolving the console problem.
So what did I do wrong? :D
Thanks and advance for every piece of help you'll bring! Cheers!
The line
export const db = firebase.database()
gets executed before firebase.initializeApp(config) has finished executing, so it will be undefined.
One way to solve this is to put the initialized Firebase object on the Vue prototype:
Vue.prototype.$firebase = Firebase.initializeApp(config)
Then, inside any of your components, such as Test.vue, you can refer to the Firebase object like this:
firebase: {
homeContent: {
source: this.$firebase.database().ref('homeContent'),
asObject: true
}
},
One caveat: This only works if you create the Vue app after you know Firebase has finished initializing. You did this correctly by putting the new Vue() statement inside firebase.auth().onAuthStateChanged() in main.js, so you will be guaranteed to have an initialized Firebase object available to you at this.$firebase in any of your components.

Meteor 1.5 : Dynamic Import for Blaze

I am having two questions:
1) I want to use Meteor 1.5 Dynamic Import for Blaze but all the examples and tutorials are given for React. So I am confused how exactly it can be used . Can anyone give examples of it.
2) I am using packages from atmospherejs.com like amcharts which I only need at Admin Dashboard side. How to dynamically import them?
Thanks in Advance!
UPDATE(Solution):
Below is homepage.html (parent template)
<template name="homepage">
Homepage Content
{{> Template.dynamic template=content}}
</template>
login.html (child template)
<template name="login">
You're logged in!
</template>
login.js
import '../homepage/homepage.js';
import './login.html';
API = function () {
BlazeLayout.render("homepage",{content: 'login'});
}
export { API }
main.js
LoadLogin = function () {
import('/imports/modules/common/login/login.js').then(function (api) {
api.API();
})
}
/lib/route.js
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
FlowRouter.route('/', {
name: 'homepage',
action() {
LoadLogin();
}
});
I am developing my own admin panel, Meteor Candy, to be driven by dynamic imports, so I am happy to share how I got it working.
First, we have the view.html:
<template name="admin">
Admin
</template>
Second, we have our JS logic:
import { Template } from 'meteor/templating';
import { Meteor } from 'meteor/meteor';
import { Blaze } from 'meteor/blaze';
import './view.html';
API = {}
API.render = function () {
Blaze.render(Template.admin, document.body);
}
export { API }
Finally, we just need to import that code and trigger our Template to be rendered into the page:
openAdmin = function () {
import('./imports/admins').then(function (api) {
api.render()
})
}
Once something runs the openAdmin() function, the templates will be imported from the server and the render function will be called.
The basic technique for dynamically importing modules in Meteor 1.5 using Blaze is as follows:
Template.theTemplate.events({
'click button'(event, instance) {
import("foo").then(Foo => {
console.log(Foo);
});
}
});
Make sure you take a close look at how your module is then imported, because apparently some refactoring may be needed when calling it in your code. For example, using "zxcvbn":
WAS
const result = zxcvbn(pwd);
IS
const result = zxcvbn.default(pwd);
It is pretty straight forward using example link https://github.com/thesaucecode/meteor-amcharts-example/blob/master/client/example2.js, you just have to write the code inside Template.MYTEMPLATE.onRendered(function(){});
On top of that you can use var chart as reactive-var.

Resources