I am trying to do a get request with Angular2 and Firebase database. The post request works perfectly well but a get request won't work. I don't know what am doing so wrong.
Here is my list.component
export class ListComponent implements OnInit {
notes = []
constructor(
private store: Store,
private noteService: ListingService
) {
}
ngOnInit() {
this.noteService.getNotes()
.subscribe();
this.store.changes.pluck('notes')
.subscribe((notes: any) => { this.notes = notes; console.log(this.notes)});
}
onCreateNote(note) {
this.noteService.createNote(note)
.subscribe();
}
onNoteChecked(note) {
this.noteService.completeNote(note)
.subscribe();
}
}
Here is my api.service
export class ApiService {
headers: Headers = new Headers({
'Content-Type': 'application/json',
Accept: 'application/json'
});
api_url: string = 'https://someapp-94b34.firebaseio.com/';
constructor(private http: Http) {
}
private getJson(response: Response) {
return response.json();
}
private checkForError(response: Response): Response {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
var error = new Error(response.statusText)
error['response'] = response;
console.error(error);
throw error;
}
}
get(path: string): Observable<any> {
return this.http.get(`${this.api_url}${path}.json`, { headers: this.headers })
.map(this.checkForError)
.catch(err => Observable.throw(err))
.map(this.getJson)
}
post(path: string, body): Observable<any> {
return this.http.post(
`${this.api_url}${path}.json`,
JSON.stringify(body),
{ headers: this.headers }
)
.map(this.checkForError)
.catch(err => Observable.throw(err))
.map(this.getJson)
}
}
Here is my listing.service
export class ListingService {
path: string = 'notes';
constructor(private storeHelper: StoreHelper, private apiService: ApiService) {}
createNote(note: Note) {
return this.apiService.post(this.path, note)
.do(savedNote => this.storeHelper.add('notes', savedNote))
}
getNotes() {
return this.apiService.get(this.path)
.do(res => this.storeHelper.update('notes', res.data));
}
completeNote(note: Note) {
return this.apiService.delete(`${this.path}/${note.id}`)
.do(res => this.storeHelper.findAndDelete('notes', res.id));
}
}
Here is my store.ts
export interface Note {
color: string,
title: string,
value: string,
id?: string | number,
createdAt?: string,
updatedAt?: string,
userId?: string
}
export interface State {
notes: Array<Note>
}
const defaultState = {
notes: []
}
const _store = new BehaviorSubject<State>(defaultState);
#Injectable()
export class Store {
private _store = _store;
changes = this._store.asObservable().distinctUntilChanged()
setState(state: State) {
this._store.next(state);
}
getState(): State {
return this._store.value;
}
purge() {
this._store.next(defaultState);
}
}
Here is my store-helper.ts
export class StoreHelper {
constructor(private store: Store) {}
update(prop, state) {
const currentState = this.store.getState();
this.store.setState(Object.assign({}, currentState, { [prop]: state }));
}
add(prop, state) {
const currentState = this.store.getState();
const collection = currentState[prop];
this.store.setState(Object.assign({}, currentState, { [prop]: [state, ...collection] }));
}
findAndUpdate(prop, state) {
const currentState = this.store.getState();
const collection = currentState[prop];
this.store.setState(Object.assign({}, currentState, {[prop]: collection.map(item => {
if (item.id !== state.id) {
return item;
}
return Object.assign({}, item, state)
})}))
}
findAndDelete(prop, id) {
const currentState = this.store.getState();
const collection = currentState[prop];
this.store.setState(Object.assign({}, currentState, {[prop]: collection.filter(item => item.id !== id)}));
}
}
And here is how am injecting the services to my app.module provider index.ts
import * as services from './services';
import { Store } from './store';
export const mapValuesToArray = (obj) => Object.keys(obj).map(key => obj[key]);
export const providers = [
Store,
...mapValuesToArray(services)
];
And app.module
import { providers } from './index'
providers: [providers, AnimationService]
The posting request works just well but the get request doesn't.
Here is the error I get:
Error encountered resolving symbol values statically.
Function calls are not supported.
Consider replacing the function or lambda with a reference to an exported function (position 3:33 in the original .ts file), resolving symbol mapValuesToArray in D:/angular2/someapp/src/app/index.ts, resolving symbol providers in D:/angular2/someapp/src/app/index.ts, resolving symbol providers in D:/angular2/someapp/src/app/index.ts, resolving symbol AppModule in D:/angular2/someapp/src/app/app.module.ts, resolving symbol AppModule in D:/angular2/someapp/src/app/app.module.ts
The AoT compiler cannot statically analyse the services you are providing, as you are using the Object.keys method to enumerate them.
You could solve the problem by adding an export to ./services.ts that explicitly lists the services:
export const SERVICE_PROVIDERS = [
ServiceOne,
ServiceTwo,
ServiceThree
];
Your import would then look like this:
import { SERVICE_PROVIDERS } from "./services";
import { Store } from './store';
export const providers = [
...SERVICE_PROVIDERS,
Store
];
Related
Building state with ngxs in angular
//Component.ts
ngOnInit(): void {
const dataInsdeStore = this.store.selectSnapshot(MarketState);
if(!dataInsdeStore.loaded){
const category = this.marketplaceService.getMarketplaceCategories().subscribe(cat => {
const item = this.marketplaceService.getMarketplaceItems().subscribe(i => {
const obj = {
categories: cat,
items: i,
loaded: true
}
this.store.dispatch(new SetMarketAction(obj))
})
})
}
const test = this.store.selectSnapshot(MarketState);
this.store.dispatch(new GetMarketStateAction())
}
Upon checking wether the state is empty or not, and dispatching SetMarketAction I get empty object anyways
//Market.actions.ts
import { MarketStateInterface } from "../interfaces/interfaces";
class SetMarketAction {
static readonly type = '[MARKET] Set';
constructor(public marketState : MarketStateInterface){}
}
class GetMarketStateAction {
static readonly type = '[MARKET] Get';
}
export { SetMarketAction, GetMarketStateAction };
//Market.state.ts
import { Action, State, StateContext } from '#ngxs/store';
import { MarketStateInterface } from '../interfaces/interfaces';
import { Injectable } from '#angular/core';
import { GetMarketStateAction, SetMarketAction } from './market.actions';
#State<MarketStateInterface>({
name: 'market',
defaults: {
categories: [],
items: [],
loaded: false,
},
})
#Injectable()
export class MarketState {
constructor() {}
#Action(GetMarketStateAction)
getMarket(ctx: StateContext<MarketStateInterface>) {
const state = ctx.getState();
console.log(state);
return state;
}
#Action(SetMarketAction)
setMarket(ctx: StateContext<MarketStateInterface>, action: SetMarketAction) {
ctx.setState(action.marketState);
}
}
Every time I conosle.log the state at any given time I get the empty array, the interface of the state is correct
A quick note and edit, it looks like this tutorial might be a winner
https://recursive.codes/blog/post/37
I am using the twilio conversation javascript client sdk on a angular 8 project.
Subscriptions, and async operations are still something I am working on understanding. My entire component that I am using twilio conversations on is below. After i will list my problems.
import {Component, Input, OnInit} from '#angular/core';
import {Client as ConversationsClient} from '#twilio/conversations';
#Component({
selector: 'app-shochat-contentcreator-chat',
templateUrl: './shochat-contentcreator-chat.component.html',
styleUrls: ['./shochat-contentcreator-chat.component.scss']
})
export class ShochatContentcreatorChatComponent implements OnInit {
constructor() { }
#Input() twiliochattoken = null;
conversationsclient;
currentconnectionstate = null;
ngOnInit(): void {
console.log('here we are and stuff tho');
let initConversations = async () => {
this.conversationsclient = await ConversationsClient.create(this.twiliochattoken);
this.conversationsclient.join().then((result) => {
console.log('here is the result of joining the conversation');
console.log(result);
});
}
this.conversationsclient.on("connectionStateChanged", (state) => {
if (state == "connecting") {
this.currentconnectionstate = 'connecting';
}
if (state == "connected") {
this.currentconnectionstate = 'connected';
}
if (state == 'disconnecting') {
this.currentconnectionstate = 'disconnecting';
}
if (state == 'disconnected') {
this.currentconnectionstate = 'disconnected';
}
if (state == 'denied') {
this.currentconnectionstate = 'denied';
}
});
this.conversationsclient.on("conversationJoined", (conversation) => {
console.log('here is the result of the conversationJoined hook');
console.log(conversation);
});
}
}
The below code snippet from the above is the problem:
this.conversationsclient.on("connectionStateChanged", (state) => {
if (state == "connecting") {
this.currentconnectionstate = 'connecting';
}
......
I am getting the error that the code cannot perform the .on function on undefined. Which makes sense, the above function is being called on the init function.
conversationsclient is undefined still. However what is the proper way to put this code? Inside the await ConversationsClient.create(.....) code?
Will that create the subscription that I want for when state changes?
Also how is my code looking based on its intent. I feel like I have missed the mark and not sure if I am close or far from hitting it.
im referencing the following docs
https://www.twilio.com/docs/chat/initializing-sdk-clients
This tutorial has the answer. I need to use a service.
chatservice:
import {EventEmitter, Injectable} from '#angular/core';
import * as Twilio from 'twilio-chat';
import Client from "twilio-chat";
import {Util} from "../util/util";
import {Channel} from "twilio-chat/lib/channel";
import {Router} from "#angular/router";
import {AuthService} from "./auth.service";
#Injectable()
export class ChatService {
public chatClient: Client;
public currentChannel: Channel;
public chatConnectedEmitter: EventEmitter<any> = new EventEmitter<any>()
public chatDisconnectedEmitter: EventEmitter<any> = new EventEmitter<any>()
constructor(
private router: Router,
private authService: AuthService,
) { }
connect(token) {
Twilio.Client.create(token).then( (client: Client) => {
this.chatClient = client;
this.chatConnectedEmitter.emit(true);
}).catch( (err: any) => {
this.chatDisconnectedEmitter.emit(true);
if( err.message.indexOf('token is expired') ) {
localStorage.removeItem('twackToken');
this.router.navigate(['/']);
}
});
}
getPublicChannels() {
return this.chatClient.getPublicChannelDescriptors();
}
getChannel(sid: string): Promise<Channel> {
return this.chatClient.getChannelBySid(sid);
}
createChannel(friendlyName: string, isPrivate: boolean=false) {
return this.chatClient.createChannel({friendlyName: friendlyName, isPrivate: isPrivate, uniqueName: Util.guid()});
}
}
component:
ngOnInit() {
this.isConnecting = true;
this.chatService.connect(localStorage.getItem('twackToken'));
this.conSub = this.chatService.chatConnectedEmitter.subscribe( () => {
this.isConnected = true;
this.isConnecting = false;
this.getChannels();
this.chatService.chatClient.on('channelAdded', () => {
this.getChannels();
});
this.chatService.chatClient.on('channelRemoved', () => {
this.getChannels();
});
this.chatService.chatClient.on('tokenExpired', () => {
this.authService.refreshToken();
});
})
this.disconSub = this.chatService.chatDisconnectedEmitter.subscribe( () => {
this.isConnecting = false;
this.isConnected = false;
});
}
I have the following state class:
import { observable, action } from 'mobx';
import axios from 'axios';
export default class AppState {
#observable user;
#observable pToken;
constructor() {
this.user = {};
this.pToken = localStorage.getItem('pToken');
}
async fetchData(query) {
const body = JSON.stringify({ query, });
const response = await axios.post('url', body, {
headers: {
'Content-Type': 'application/json',
token: localStorage.getItem('pToken')
}
});
const user = response.data.data.user;
console.log('Got user', user);
this.setUser(user);
}
#action setUser(user) {
this.user = user;
}
}
and in my component:
#inject('store')
#observer
export default class Header extends Component {
constructor(props) {
super(props);
this.store = this.props.store.appState;
}
render() {
const { user } = this.store;
console.log('store', this.store);
return (
<header className='header'>
User - {user.username}
</header>
);
}
}
Unfortunately, the state user property returns a Proxy object, while the user log shows the user object. Any idea what I'm missing?
Everything is working as intended, MobX v5 relies on proxies under the hood so when you log observable objects it usually shows some internal implementation.
You can use toJS MobX method console.log(toJS(user)) or just destructure user object console.log({ ...user })
toJS docs: https://mobx.js.org/refguide/tojson.html
I am trying to make role guard for graphql field. Something like this:
import { Field, ObjectType } from 'type-graphql';
import { Column, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn } from 'typeorm';
import Role from '../role/role.entity';
#ObjectType()
#Entity()
class User {
#Field()
#PrimaryGeneratedColumn()
readonly id: number;
#Field()
#Column()
#Guard('USER_SEE_NAME') //this line
name: string;
#Field()
#Column()
surname: string;
}
export default User;
The goal is that if a user does not have a required role the field will be sent to the client with null value.
I have found out that I should use class-transformer but I haven't found any examples of nestjs. I have also looked into nestjs documentation but there are only examples of built-in decorators and they are not used in ObjectType.
I would use Authorized decorator but I need to access nestjs context to get userId and I haven't found a way to do it.
Do you now about some examples or a ways to do it?
So after a few days I found a solution. I wrote a custom Interceptor that looks like this:
import {
Injectable,
ExecutionContext,
CallHandler,
ClassSerializerInterceptor,
Inject,
} from '#nestjs/common';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Observable } from 'rxjs';
// eslint-disable-next-line import/no-extraneous-dependencies
import { map } from 'rxjs/operators';
import { GqlExecutionContext } from '#nestjs/graphql';
import { ClassTransformOptions } from '#nestjs/common/interfaces/external/class-transform-options.interface';
import { PlainLiteralObject } from '#nestjs/common/serializer/class-serializer.interceptor';
import { CLASS_SERIALIZER_OPTIONS } from '#nestjs/common/serializer/class-serializer.constants';
import { loadPackage } from '#nestjs/common/utils/load-package.util';
import AuthService from './auth.service';
const REFLECTOR = 'Reflector';
let classTransformer: any = {};
#Injectable()
class ResourceInterceptor extends ClassSerializerInterceptor {
constructor(
#Inject(AuthService) private authService: AuthService,
#Inject(REFLECTOR) protected readonly reflector: any,
) {
super(reflector);
classTransformer = loadPackage('class-transformer', 'ClassSerializerInterceptor', () =>
// eslint-disable-next-line global-require
require('class-transformer'),
);
// eslint-disable-next-line global-require
require('class-transformer');
}
serializeCustom(
response: PlainLiteralObject | Array<PlainLiteralObject>,
options: ClassTransformOptions,
user: number,
): PlainLiteralObject | PlainLiteralObject[] {
const isArray = Array.isArray(response);
if (!(typeof response === 'object') && response !== null && !isArray) {
return response;
}
return isArray
? (response as PlainLiteralObject[]).map(item => this.transformToClass(item, options))
: this.transformToGuard(this.transformToClass(response, options), user);
}
transformToClass(plainOrClass: any, options: ClassTransformOptions): PlainLiteralObject {
return plainOrClass && plainOrClass.constructor !== Object
? classTransformer.classToClass(plainOrClass, options)
: plainOrClass;
}
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const options = this.getContextOptionsCustom(context);
const ctx = GqlExecutionContext.create(context);
const { user } = ctx.getContext().req;
return next.handle().pipe(
map((res: PlainLiteralObject | Array<PlainLiteralObject>) => {
return this.serializeCustom(res, options, user);
}),
);
}
private getContextOptionsCustom(context: ExecutionContext): ClassTransformOptions | undefined {
return (
this.reflectSerializeMetadataCustom(context.getHandler()) ||
this.reflectSerializeMetadataCustom(context.getClass())
);
}
private reflectSerializeMetadataCustom(
obj: object | Function,
): ClassTransformOptions | undefined {
return this.reflector.get(CLASS_SERIALIZER_OPTIONS, obj);
}
async transformToGuard(response, userId: number) {
// eslint-disable-next-line no-restricted-syntax
for (const key of Object.keys(response)) {
const item = response[key];
// eslint-disable-next-line no-underscore-dangle
if (typeof item === 'object' && item !== null && item.__RESOURCE_GUARD__ === true) {
// eslint-disable-next-line no-await-in-loop
response[key] = (await this.authService.hasAccess(userId, item.resources))
? response[key].value
: null;
}
}
return response;
}
}
export default ResourceInterceptor;
Usage:
#UseInterceptors(ResourceInterceptor)
async userGetLogged(#CurrentUser() userId: number) {
return this.userService.findById(userId);
}
I'm currently doing a setup of an ngrx app. One of the goal is to use ngrx to train myself even if the application is too small.
It's a small project for beer inventory management.
I've a component in which I want to display my beer list:
export class BeerListComponent implements OnInit {
availableBeers$: Beer[];
constructor(private breadcrumbService: BreadcrumbService,
private beerService: BeersService,
private store: Store<fromBeer.BeerState>) {
this.breadcrumbService.setItems([
{ label: 'Beers' },
{ label: 'List' }
]);
}
ngOnInit() {
this.store.select(fromBeer.getAvailableBeers).subscribe((beers: Beer[]) => {
console.log(beers);
this.availableBeers$ = beers;
})
console.log('fetching beers');
this.beerService.fetchBeersList();
}
}
my beer service does the following:
export class BeersService {
private firebaseSubscription: Subscription[] = [];
constructor(
private db: AngularFirestore,
private store: Store<fromBeers.BeerState>) { }
fetchBeersList() {
this.firebaseSubscription.push(this.db
.collection('beers')
.valueChanges()
.subscribe((beers: Beer[]) => {
console.log("Received a firebase change");
console.log(beers);
this.store.dispatch(new SetAvailableBeers(beers));
}, error => {
console.log(error);
}));
}
}
and here are my reducer/actions:
Actions
export enum BeersActionTypes {
SET_AVAILABLE_BEERS = '[Beers] SET_AVAILABLE_BEERS'
};
export class SetAvailableBeers implements Action {
readonly type = BeersActionTypes.SET_AVAILABLE_BEERS;
constructor(public payload: Beer[]) {
console.log(payload);
}
}
export type BeersActions
= SetAvailableBeers;
Reducer
export interface BeerState {
availableBeers: Beer[];
};
const initialState: BeerState = {
availableBeers: []
};
export function beersReducer(state = initialState, action: BeersActions): BeerState {
switch (action.type) {
case BeersActionTypes.SET_AVAILABLE_BEERS: {
console.log("Setting available beerse")
return {
...state,
availableBeers: action.payload
};
}
default: {
return state;
}
}
}
export const getAvailableBeers = (state: BeerState) => state.availableBeers;
What I cannot understand:
I receive beers from firebase, but my component never gets the update. If I check the chrome dev tools, I only get one this undefined but this doesn't get updated after.
Here are my logs:
I feel I did not register correctly to my ngrx state, but I cannot figure out what I did wrong?
I think I found my error!
I was subscribing directly to the beerReducers.getAvailableBeers and not the one of my app.reducer(which contains the CreateSelector and stuff)