I cannot show my data from my firebase on my app. I am really new to this and I don't know what to do. I can't find any solution for this on the internet.
This is my typescript code:
import { Component, OnInit } from "#angular/core";
import { ActivatedRoute, ActivatedRouteSnapshot } from "#angular/router";
import { Item } from "./item";
import { ItemService } from "./item.service";
import { EventData } from "tns-core-modules/data/observable";
import { Label } from "tns-core-modules/ui/label";
import { listener } from "#angular/core/src/render3";
const firebase = require("nativescript-plugin-firebase");
const firebaseWebApi = require("nativescript-plugin-firebase/app");
#Component({
selector: "ns-details",
moduleId: module.id,
templateUrl: "./item-detail.component.html",
})
export class ItemDetailComponent implements OnInit {
item: Item;
public oneway;
public stuff = firebaseWebApi.database().ref("/WaterStatus")
.once("value")
.then(result => console.log(JSON.stringify(result)))
.catch(error => console.log("Error: " + error));
constructor(
private itemService: ItemService,
private route: ActivatedRoute
) { }
ngOnInit(): void {
const id = +this.route.snapshot.params["id"];
this.item = this.itemService.getItem(id);
var onChildEvent = function(oneway) {
console.log("Water Status: " + JSON.stringify(oneway.value));
};
// listen to changes in the /users path
firebase.addChildEventListener(onChildEvent, "/WaterStatus").then(
function(listenerWrapper) {
var path = listenerWrapper.path;
var listeners = listenerWrapper.listeners;
}
);
firebase.getValue('/WaterStatus')
.then(result => console.log(JSON.stringify(result)))
.catch(error => console.log("Error: " + error));
}
}
and this is my html:
<ActionBar title="Details" class="action-bar"></ActionBar>
<FlexboxLayout flexDirection="column" class="page">
<FlexboxLayout class="m-15">
<Label class="h2" [text]="item.id + '. '"></Label>
<Label class="h2" [text]="item.name"></Label>
</FlexboxLayout>
<Label class="h3" [text]="item.role"></Label>
<!-- <Button text="Tap Me!" tap="onTap" class="btn btn-primary btn-active"></Button> -->
<br>
<br>
<Label class="h3 p-15" text='{{oneway}}' textWrap="true">{{oneway}}</Label>
<Label class="h3 p-15" text='{{stuff}}' textWrap="true"></Label>
<Label class="h3 p-15" text='{{last}}' textWrap="true">{{last}}</Label>
</FlexboxLayout>
How can I show my data on my app?
Some say that I should do Promise resolve but I don't really know how to integrate it with that.
screenshot:
screenchot
Looking at your code, the [object Promise] comes from <Label class="h3 p-15" text='{{stuff}}' textWrap="true"></Label> (please confirm by removing the other tables or adding a different color to this label).
In fact, stuff is initialized as a promise. Instead, you have to remove that initialization, and inside ngOnInit(), do:
firebaseWebApi.database().ref("/WaterStatus")
.once("value")
.then(result => {
console.log(JSON.stringify(result)));
this.stuff = result; // or result.something?
})
.catch(error => console.log("Error: " + error));
I am not a firebase expert, but I hope it helps.
Related
I'm using next-auth 4.18.4 and can't figure out how to set up the Credential provider properly. At this point, when the user logs in, the status remains unauthenticated, and only updates to authenticated when I refresh the page. This is what I have in api/auth/[...nextauth].ts:
import NextAuth from 'next-auth'
import CredentialsProvider from 'next-auth/providers/credentials'
import { verifyPassword } from '../../../lib/auth'
import conn from '../../../lib/db'
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
const query = `SELECT * FROM users WHERE username = $1`
const values = [ credentials.username ]
let user
try {
const result = await conn.query(query, values)
if (result.rows.length > 0) user = result.rows[0]
} catch (err) {
console.log(`Error fetching user from DB: ${err.stack}`)
throw new Error(err)
}
if (!user) throw new Error('No user found!')
const isValid = await verifyPassword(
credentials?.password,
user.password
)
if (!isValid) throw new Error('Could not log you in!')
return {
uid: user.id,
username: user.username,
profilePic: user.profile_pic
}
},
}),
],
})
This is my login page:
import { useForm } from 'react-hook-form'
import { z } from 'zod'
import { zodResolver } from '#hookform/resolvers/zod'
import { signIn } from 'next-auth/react'
import { useRouter } from 'next/router'
import Input from "../components/input"
const validationSchema = z
.object({
userName: z
.string()
.min(1, { message: 'Username is required' })
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{5,10}$/, {
message: '5-10 upper and lowercase letters, and digits',
}),
password: z
.string()
.min(5, { message: 'Between 5-10 characters' })
.regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{5,10}$/, {
message: 'Upper and lowercase letters, and digits',
})
})
export default function Auth() {
const {
register,
handleSubmit,
watch,
formState: { errors, isValid },
setValue
} = useForm({
mode: 'all',
resolver: zodResolver(validationSchema),
})
const router = useRouter()
async function submitHandler(data: any) {
const result = await signIn('credentials', {
redirect: false, // don't redirect if user enters wrong credentials
username: data.userName,
password: data.password
})
// console.log(result) // testing
// If the 'error' property is null (meaning log in was successful)
if (!result?.error) {
// Let's clear the input fields
setValue('userName', '')
setValue('password', '')
// And redirect the user to the main page
router.replace('/')
} else {
// If the 'error' property was false, let's print the login error
console.log(`Error: ${JSON.stringify(result.error)}`)
}
}
return (
<div className='text-white max-w-4xl mx-auto pt-10 pb-20 px-2'>
<h1 className='text-2xl text-center pb-8'>Log in</h1>
<form
onSubmit={handleSubmit(submitHandler)}
className='space-y-4 flex flex-col items-center '
>
<Input
id='userName'
type='text'
label='Username'
register={register}
registerOptions={{ required: true }}
errors={errors}
isRequired={true}
/>
<Input
id='password'
type='password'
label='Password'
register={register}
registerOptions={{ required: true }}
errors={errors}
isRequired={true}
/>
<button
type='submit'
disabled={!isValid}
className={`p-3 border-[1px] border-slate-500 rounded-md hover:enabled:bg-white hover:enabled:bg-opacity-20 disabled:cursor-not-allowed w-[90%]`}
>
{isValid ? 'Log In' : 'Please, fill the form'}
</button>
</form>
</div>
)
}
And my index page:
import { useSession } from 'next-auth/react'
export default function Home() {
const { data: session, status } = useSession()
console.log(status);
return (
<div>
<h1 className='text-2xl text-white text-center p-4'>Home Page</h1>
{status === 'authenticated' ?
(<h2 className='text-2xl text-white p-14'>Logged in!</h2>)
:
(<h2 className='text-2xl text-white p-14'>Not logged in!</h2>)
}
</div>
)
}
And the session provider in _app.ts:
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Layout from '../components/layout'
import { SessionProvider } from 'next-auth/react'
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
<Layout>
<Component {...pageProps} />
</Layout>
</SessionProvider>
)
}
By the way, I forgot to add that after logging in, I can see the next-auth.session cookie being created in the browser, but still, status doesn't change until I reload.
I am trying to setup a Sendgrid Newletter signup, using the following code, stored in pages/api
import axios from "axios";
export default async function handler(req, res) {
if (req.method === "PUT") {
axios
.put(
"https://api.sendgrid.com/v3/marketing/contacts",
{
contacts: [{ email: `${req.body.mail}` }],
list_ids: [process.env.SENDGRID_MAILING_ID],
},
{
headers: {
"content-type": "application/json",
Authorization: `Bearer ${process.env.SENDGRID_SECRET}`,
},
}
)
.then((result) => {
// return
res.status(200).send({
message:
"Your email has been succesfully added to the mailing list. Welcome 👋",
});
})
.catch((err) => {
// return
res.status(500).send({
message:
"Oups, there was a problem with your subscription, please try again or contact us",
});
});
}
}
The front end component looks similar to
import axios from "axios";
import { toast } from "react-toastify";
import { useState } from "react";
const MailingList = () => {
const [mail, setMail] = useState(null);
const [loading, setLoading] = useState(false);
const subscribe = () => {
setLoading(true);
axios
.put("api/mailingList", {
mail,
})
.then((result) => {
if (result.status === 200) {
toast.success(result.data.message);
setLoading(false);
}
})
.catch((err) => {
console.log(err);
setLoading(false);
});
};
return (
<div className='my-10'>
<hr className='my-5' />
<h2 className='text-3xl md:text-3xl font-semibold font-title'>
Stay Tuned!
</h2>
<label className='label'>
<p className='text-lg max-w-xl text-center m-auto leading-9'>
Want to be the first to know when SupaNexTail launches and get an
exclusive discount? Sign up for the newsletter!
</p>
</label>
<div className='mt-5'>
<input
onChange={(e) => {
setMail(e.target.value);
}}
type='email'
placeholder='Your email'
className='input input-primary input-bordered'></input>
<button
onClick={subscribe}
className={`btn ml-3 ${
loading ? "btn-disabled loading" : "btn-primary"
}`}>
I'm in!
</button>
</div>
<hr className='my-5' />
</div>
);
};
export default MailingList;
The emails are actually being added to the Sendgrid mailing list, but no response error is being displayed, email field is not cleared. And this is displayed in the console:
API resolved without sending a response for /api/MailingList, this may result in stalled requests.
The same console warning is displayed when return res.status(..
Need some advice on how to solve this!
I'm learning Vue 3 composition API and Pinia. I'm making a todo.
When I submit a todo data through Pinia, I can submit to the DB, but it won't re-render until reload the page.
Do I need to use 'watch' to watch the state todos:[] and execute fetchTodos()?
any good solution?
here both codes, hope someone can help me. Thank you in advance.
----- VUE -----
<script setup>
import { ref, onMounted } from 'vue'
import { storeToRefs } = from 'pinia'
import { useTodoStore } from '../store/todo'
const store = useTodoStore()
const { getTodos } = storeToRefs(store)
onMounted(() => {
store.fetchTodos()
})
const todo = ref('')
const initForm = () => {
todo.value = ''
}
// submit via Pinia
const onSubmitToPinia = () => {
const payload = {
todo: todo.value,
}
store.addTodoFromPinia(payload)
initForm()
store.fetchTodo()
}
</script>
<template>
<h4>TODO</h4>
<!-- form addTodo -->
<form class="row g-4">
<div class="col-auto">
<input
class="form-control"
v-model="newName"
type="text"
placeholder="todo">
</div>
<div>
<button
class="btn btn-primary"
type="button"
#click="onSubmitToPinia(payload)">
submit through pinia</button>
</div>
</form>
<!-- render data from pinia -->
<div class="todo"
v-for="getTodo in getTodoss.todo"
:key="getTodo.id">
<b class="ms-2">{{ getTodo.todo }}</b>
</div>
</template>
---- PINIA ----
import { defineStore } from 'pinia'
import axios from "axios"
export const useAboutStore = defineStore('todo',{
state: () => {
return {
todos: []
}
},
getters: {
getTodos(state) {
return state.todos
}
},
actions: {
async fetchTodos() {
try {
const data = await axios.get('http://localhost:5000/todo')
this.todos = data.data
}
catch (error) {
alert(error)
console.log(error)
}
},
addTodoFromPinia(payload) {
const path = 'http://localhost:5000/todo'
axios.post(path, payload)
}
},
})
You don't need to use storeToRefs to accomplish what you want nor do you need to watch the state of the store.
<template>
<div class="todo"
v-for="getTodo in store.todos"
:key="getTodo.id">
<b class="ms-2">{{ getTodo.todo }}</b>
</div>
</template>
If for any reason the vue complains that the array is empty put a v-if checking if the store.todos.length is != 0.
And also fix your typos.
If the problem persists show me your new code and I help you again.
To demonstrate a component I try to write custom state and methods for a story.
For example, I have a component ListItems who accepts an array of string as Input.
In the story of this component I want to show an interactive example of the usage of this component.
So my story will have internal state "items" and internal method "addItem"
I know how to do that with React, but I'm stuck with Angular.
Here is a React way to do that:
(View in codesandbox)
// ListItems.tsx
import React from "react";
export type ListItemsProps = { items: string[] };
export const ListItems = ({ items = [] }: ListItemsProps) => {
return (
<ul>
{items.map((item, key) => (
<li key={key}>{item}</li>
))}
</ul>
);
};
// ListItems.stories.tsx
import React, { useState } from "react";
import { ListItems } from "./ListItems";
export default {
title: "ListItems",
component: ListItems
};
export const Text = () => {
const [items, setItems] = useState(["Demo Item"]);
const [value, setValue] = useState("");
const addItem = () => {
setItems([...items, value]);
setValue("");
};
return (
<div>
<ListItems items={items} />
<input value={value} onChange={(e) => setValue(e.target.value)} />
<input type="submit" onClick={addItem} value="add" />
</div>
);
};
};
How can I write the same story with following Angular Component ?
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-list-items",
template: `<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>`
})
export default class ListItems implements OnInit {
#Input() items: string[] = [];
constructor(){}
ngOnInit(): void {}
}
Finally I found a solution on Angular, but it's not an elegant one...
Maybe someone know a better way !
And I can't find a solution to show the code story template on "Show code" feature.
import { Story, Meta } from '#storybook/angular/types-6-0';
import { ListItemsComponent } from './list-items.component';
import { Component } from '#angular/core';
export default {
title: 'Demo/ListItems',
component: ListItemsComponent,
} as Meta;
const Template: Story<ListItemsComponent> = (args: ListItemsComponent) => ({
props:args,
});
export const BasicDemo = Template.bind({})
BasicDemo.args={
items: ["Basic Demo", "Without interaction"]
}
// Create a dedicated component for the interactive story
#Component({
selector: 'story-list-items',
template: `
<core-list-items [items]="items"></core-list-items>
<input type="text" [(ngModel)]="value" /><button (click)="addItem()">add</button>
`,
})
class InteractiveDemoComponent{
items = [];
value: string = '';
addItem(){
this.items = [...this.items, this.value];
this.value = ""
}
}
const InteractiveTemplate: Story<ListItemsComponent> = (args: ListItemsComponent) => ({
props:args,
component: InteractiveDemoComponent,
});
export const InteractiveDemo = InteractiveTemplate.bind({});
InteractiveDemo.args = {
items: ["Interactive Demo"]
}
I am trying to use Redux in my React application to update the user profile within my Firebase database from my react component.
This is my component:
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { firestoreConnect } from "react-redux-firebase";
import { compose } from "redux";
import { editProfile } from "../../store/actions/editProfileActions";
class UserProfile extends Component {
state = {
firstName:"",
initials:"",
lastName:""
};
onChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
onSubmit = e => {
e.preventDefault();
console.log(this.state);
this.props.editProfile(this.state);
}
render() {
const { auth, profile } = this.props;
console.log(profile);
if (auth.isEmpty) return <Redirect to="/home" />;
return (
<div className="container">
<form onSubmit={this.onSubmit} className="white">
<h5 className="grey-text text-darken-3">Edit Profile</h5>
<div className="input-field">
<label htmlFor="title">First Name: {profile.firstName}</label>
<input type="text" id="firstName" onChange={this.onChange} />
</div>
<div className="input-field">
<label htmlFor="title">Initials: {profile.initials}</label>
<input type="text" id="initials" onChange={this.onChange} />
</div>
<div className="input-field">
<label htmlFor="title">Last Name: {profile.lastName}</label>
<input type="text" id="lastName" onChange={this.onChange} />
</div>
<div className="input-field">
<button className="btn black z-depth-0">Submit</button>
{ }
</div>
</form>
</div>
)
}
};
const mapStateToProps = state => {
return {
auth: state.firebase.auth,
profile: state.firebase.profile,
};
};
const mapDispatchToProps = dispatch => {
return {
editProfile: edit => dispatch(editProfile(edit))}
}
export default compose(
connect(mapStateToProps, mapDispatchToProps),
firestoreConnect([
{ collection: "profile"}
])
)(UserProfile);
The component correctly displays the current user information.
This is the action I have set up:
return async (dispatch, getState, { getFirestore, getFirebase }) => {
const firebase = getFirebase();
const user = await firebase
.auth()
.currentUser
.updateProfile({
firstName: profile.firstName
});
dispatch({ type: "EDITPROFILE_SUCCESS", user })
console.log("user = " + profile.firstName);
};
}
When I log the entered profile.firstName I get the entered data.
And my reducer:
const editProfileReducer = (state, action) => {
switch (action.type) {
case "EDITPROFILE_ERROR":
return {
...state,
editError: action.error
};
case "EDITPROFILE_SUCCESS":
return {
...state
};
default:
return state;
}
}
export default editProfileReducer;
Any idea what I am missing here?
In your reducer change the like below
case "EDITPROFILE_SUCCESS":
return {
...state,
user:action.user
};
Above is if you want to update the whole user object
If you want to change only name then
Let’s assume that profileName is in user object then
case "EDITPROFILE_SUCCESS":
return {
...state,
user:Object.assign({}, state.user, profileName:action.user.profileName)
};