How to access FB global from Angular2 service? - facebook-graph-api

I'm trying to use FB SDK from an Angular2 project created with the new angular CLI. I created the following service to initialize the Facebook library, added fbsdk typings and everything compiles but I cant access the FB global variable from anywhere in the project but the "winwow.fbAsyncInit" function. I can check FB object from console perfectly, but cant access it from NG2 code. ¿Any idea of where the problem might be?
import { Injectable, OnInit } from '#angular/core'
import { FACEBOOK_APPID } from '../constants'
#Injectable()
export class fbService implements OnInit{
constructor(){}
ngOnInit(){
if (!window.fbAsyncInit) {
window.fbAsyncInit = function () {
FB.init({
appId: FACEBOOK_APPID,
xfbml: false,
version: 'v2.6'
});
FB.api("/me",null,()=>{})
console.log(FB)
};
}
this.initFB()
}
initFB(){
var js, id = 'facebook-jssdk', ref = document.getElementsByTagName('script')[0];
if (document.getElementById(id)) {
return;
}
js = document.createElement('script');
js.id = id;
js.async = true;
js.src = "//connect.facebook.net/en_US/sdk.js";
ref.parentNode.insertBefore(js, ref);
}
getPost(page:string){
FB.api(`/${page}/feed?limit=1`,null,(response)=>{console.log(response)})
}
}

The key is in the call to this.zone.run(callback) to wrap the callback and reinsert it in the Angular 2 lifecycle.
I initialize the SDK in the service constructor, which may introduce some delay compared to loading it right away. Haven't found a workaround yet.
I still haven't decided if I'll provide an accessor to FB once initialized or wrapper methods, I'll leave that to you.
#Injectable()
export class FbsdkService {
public ready = new BehaviorSubject<boolean>(false);
constructor(
private zone: NgZone) {
this.loadSdkAsync(() => {
FB.init({
appId: "XXXXXXXXXXX",
status: false,
xfbml: false,
version: "v2.7"
});
this.ready.next(true);
});
}
loadSdkAsync(callback: () => void) {
window.fbAsyncInit = () => this.zone.run(callback);
// Load the Facebook SDK asynchronously
const s = "script";
const id = "facebook-jssdk";
var js, fjs = document.getElementsByTagName(s)[0];
if (document.getElementById(id)) return;
js = document.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs)
}
}

I had similar issue and this source helped me a lot- Building CrossPlatform Desktop Applications with Electron
import { Injectable, NgZone } from '#angular/core';
import { BehaviorSubject } from "rxjs/Rx";
import { Http } from '#angular/http';
declare var FB: any;
#Injectable()
export class FbsdkService {
public ready = new BehaviorSubject<boolean>(false);
public endpointBase = 'http://graph.facebook.com';
constructor(private zone: NgZone, private http: Http) {
}
public loadSdk() {
this.loadAsync(() => { });
}
public loadAsync(callback: () => void) {
window.fbAsyncInit = () => this.zone.run(callback);
const s = "script";
const id = "facebook-jssdk";
var js: any, fjs = document.getElementsByTagName(s)[0];
if (document.getElementById(id)) return;
js = document.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}
public getLoginStatus() {
FB.getLoginStatus((response: any) => { console.log(response); });
}
public getProfile() {
return new Promise((resolve, reject) => {
let fields = [
"id", "name", "email", "cover", "birthday"
];
FB.api(`/me?fields=${fields.toString()}`, (response: any) => {
resolve(response);
});
});
}
}

Related

my token sends user_id How I can get it by localStorage in Angular?

I need help trying to figure it out, i am using django as backend and Angular as frontend.
My django backend pass a token so it can be acessed in frontend by login.
login.ts
onLogin() {
this.service.loginUser(this.input).subscribe(
response => {
console.log(response)
this.jwttoken.setToken(response['token']);
this.jwttoken.getItem(response);
this.router.navigate(['dashboard']);
},
error => {
console.log('error', error);
}
i save it in a localstorage that can be acessed on my service
jwttoken service
jwtToken : string
decodedToken: {[key: string]: string}
public storage: Storage;
constructor() {
this.storage = window.localStorage;
}
setToken(token: string){
if (token) {
this.jwtToken = token;
}
}
getItem(key: string) {
if(this.storage){
localStorage.setItem('token',(key));
}
return null;
}
i need to have my user id that i can see on my web browser console.
{"token":"[object Object]","d34330659cba7cf64e8414f83aa6522f55b0f978":"d34330659cba7cf64e8414f83aa6522f55b0f978","[object Object]":"{"token":"d34330659cba7cf64e8414f83aa6522f55b0f978","user_id":1,"email":"admin#admin.com"}"}
this is where i need to access my user id, so i can send it to my html file
export class RegularComponent implements OnInit {
patient_code: any;
number_tumor: any;
tumor_size: any;
tumor_volume: any;
biopsy_date: any;
hp_lote_number: any;
closeResult: string;
userlists: any;
user_id: any;
constructor(private service: SharedService, private modalService: NgbModal, private jwtstorage: JWTTokenServiceService) { }
localstorage = JSON.stringify(this.jwtstorage.storage).replace(/\\/g, "");
ngOnInit() {
// this.getUserlist();
console.log(this.localstorage);
}
// getUserlist() {
// let observable = this.service.getUsersList();
// observable.subscribe((data) => { this.userlists = data; console.log(data); return data; }); }
open(content) {
this.modalService.open(content,{ariaLabelledBy: 'modal-basic-title', size: 'lg'}).result.then((result) => {
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
}
I searched all around, and I can't figure it out. Could you explain to me how I can do this?
I just need the user_id of that string that cames from the localstorage. Thank you.

How to unit test VueJS watcher on $route

I'm testing a Single file component that uses vue router to watch $route. The problem is that I can't get the test to both change the route and trigger the watcher's function.
The test file:
import { createLocalVue, shallow } from 'vue-test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
const localVue = createLocalVue();
localVue.use(Vuex);
const $route = {
path: '/my/path',
query: { uuid: 'abc' },
}
wrapper = shallow({
localVue,
store,
mocks: {
$route,
}
});
it('should call action when route changes', () => {
// ensure jest has a clean state for this mocked func
expect(actions['myVuexAction']).not.toHaveBeenCalled();
vm.$set($route.query, 'uuid', 'def');
//vm.$router.replace(/my/path?uuid=def') // tried when installing actual router
//vm.$route.query.uuid = 'def'; // tried
//vm.$route = { query: { uuid: 'def'} }; // tried
expect(actions['myVuexAction']).toHaveBeenLastCalledWith({ key: true });
});
My watch method in the SFC:
watch: {
$route() {
this.myVuexAction({ key: true });
},
},
How do you mock router in such a way that you can watch it and test the watch method is working as you expect?
This is how I'm testing a watch on route change that adds the current route name as a css class to my app component:
import VueRouter from 'vue-router'
import { shallowMount, createLocalVue } from '#vue/test-utils'
import MyApp from './MyApp'
describe('MyApp', () => {
it('adds current route name to css classes on route change', () => {
// arrange
const localVue = createLocalVue()
localVue.use(VueRouter)
const router = new VueRouter({ routes: [{path: '/my-new-route', name: 'my-new-route'}] })
const wrapper = shallowMount(MyApp, { localVue, router })
// act
router.push({ name: 'my-new-route' })
// assert
expect(wrapper.find('.my-app').classes()).toContain('my-new-route')
})
})
Tested with vue#2.6.11 and vue-router#3.1.3.
I checked how VueRouter initializes $route and $router and replicated this in my test. The following works without using VueRouter directly:
const localVue = createLocalVue();
// Mock $route
const $routeWrapper = {
$route: null,
};
localVue.util.defineReactive($routeWrapper, '$route', {
params: {
step,
},
});
Object.defineProperty(localVue.prototype, '$route', {
get() { return $routeWrapper.$route; },
});
// Mock $router
const $routerPushStub = sinon.stub();
localVue.prototype.$router = { push: $routerPushStub };
const wrapper = shallowMount(TestComponent, {
localVue,
});
Updating $route should always be done by replacing the whole object, that is the only way it works without using a deep watcher on $route and is also the way VueRouter behaves:
$routeWrapper.$route = { params: { step: 1 } };
await vm.wrapper.$nextTick();
Source: install.js
Its working for me
let $route = {
name: 'any-route',
};
We defined a $route and we called like
wrapper = mount(YourComponent, {
mocks: {
$route,
},
});
and my componente is like this
#Watch('$route', { deep: true, immediate: true, })
async onRouteChange(val: Route) {
if (val.name === 'my-route') {
await this.getDocumentByUrl();
await this.allDocuments();
}
};
pd: I use typescript, but this work with the another format
and finally my test
it('my test', ()=>{
const getDocumentByUrl = jest.spyOn(wrapper.vm, 'getDocumentByUrl');
const allDocuments = jest.spyOn(wrapper.vm, 'allDocuments');
wrapper.vm.$route.name = 'my-route';
await flushPromises();
expect(getDocumentByUrl).toHaveBeenCalled();
expect(allDocuments).toHaveBeenCalled();
})
The way to do this actually is to use vue-test-utils wrapper method, setData.
wrapper.setData({ $route: { query: { uuid: 'def'} } });

Angular 2: BehaviorSubject/Subject does not work outside constructor

Hi I need pass the data from one component to another, for this I am using the class BehavorSubject(I tried too with Subject class, but doesnt works for me). This is my code:
Home page has a filter, and when is selected a filter, it called the service and it service should change a variable of homePage
HomePage.ts
#Component({
providers: [PatientService],
})
export class HomePage {
subscription: Subscription;
constructor( public auth: AuthService,
public patientService: PatientService) {
this.subscription = this.patientService.nameGiven.subscribe(
nameGiven => {
this.patientsByElement = nameGiven.toString();
});
------ more code---
}
Filtro.ts
export class FiltroPage {
showFilter(filter : FiltroT): void{
... code ...
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.PatientService.getPatientsByTags(this.token,this.filterSelected);
} , 1000);
}
}
patient-service.ts
import { Subject } from 'rxjs/Subject';
import { Observable ,BehaviorSubject } from 'rxjs/Rx';
#Injectable()
export class PatientService {
nameSource = new BehaviorSubject("asd");
nameGiven = this.nameSource.asObservable();
this.nameSource.next('hi!!!'); //**it works but only in the constructor**
this.nameGiven.subscribe(()=>{
console.log("it changed");
});
getPatientsByTags(token: String, tags: Array<string>){
return new Promise(resolve => {
this.http.get(ConnectionParams.DevEnv + ProceduresNames.TagsByPatient + ProceduresNames.TagIdEtiqueta + tags, options)
.map(res => res.json())
.subscribe(data => {
if(data.data.poAnicuRegistros){
console.log("here")
this.nameSource.next('hi TON :/'); // <-- ***here is the problem. It doesnt work***
}
else
console.log("XX");
resolve( this.data);
});
});
}
}
Finally i didn't use the BehaviorSubject/Subject, i pass the data from the filter to Homepage of this way :
HomePage.ts
public popoverCtrl: PopoverController
//code ...
showFilter(myEvent) {
let popover = this.popoverCtrl.create(FiltroPage, {
showConfirm: (x) => {
//do something with the data received from the filter
}
});
popover.present({
ev: myEvent
});
}
Filter.ts
//code...
params: NavParams;
showConfirm() {// function that return the data to homePage
this.params.get('showConfirm')(this.patientsBytag);
}

Retrieving data from a couchdb

.Am working on an app using ionic 2. I have my data in couchdb about 9 differents items. How can i display each data from the database corresponding to the item clicked. The items are in a list?
This s the provider diagnosis.ts
import { Injectable } from '#angular/core';
import PouchDB from 'pouchdb';
#Injectable()
export class Diagnosis{
data: any;
db: any;
remote: any;
constructor() {
this.db = new PouchDB('ezy');
this.remote = 'http://localhost:5984/ezy';
let options = {
live: true,
retry: true,
continuous: true
};
this.db.sync(this.remote, options);
}
getTodos() {
if (this.data) {
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.db.allDocs({
include_docs: true
}).then((result) => {
this.data = [];
let docs = result.rows.map((row) => {
this.data.push(row.doc);
});
resolve(this.data);
this.db.changes({live: true, since: 'now', include_docs: true}).on('change', (change) => {
this.handleChange(change);
});
}).catch((error) => {
console.log(error);
});
});
}
createTodo(todo){
this.db.post(todo);
}
getTodo(todo){
this.db.get(todo);
}
updateTodo(todo){
this.db.put(todo).catch((err) => {
console.log(err);
});
}
deleteTodo(todo){
this.db.remove(todo).catch((err) => {
console.log(err);
});
}
handleChange(change){
let changedDoc = null;
let changedIndex = null;
this.data.forEach((doc, index) => {
if(doc._id === change.id){
changedDoc = doc;
changedIndex = index;
}
});
//A document was deleted
if(change.deleted){
this.data.splice(changedIndex, 1);
}
else {
//A document was updated
if(changedDoc){
this.data[changedIndex] = change.doc;
}
//A document was added
else {
this.data.push(change.doc);
}
}
}
}
provider usage is as
.ts
constructor(public navCtrl: NavController, public navParams: NavParams,public diagnose:Diagnosis) {
this.pet = "puppies";
console.log(diagnose.getTodos());
diagnose.getTodos().then(result=>{
this.pest = result;
console.log(result);
})
}
.html
<ion-grid>
<ion-row>
<ion-col *ngFor="let val of pest" width-100>
<ion-list>
<ion-item><h3>{{val.name}}</h3></ion-item>
<ion-item><h3>{{val.description}}</h3></ion-item>
<ion-item><h3>{{val.disease}}</h3></ion-item>
<ion-item><h3>{{val.prevention}}</h3></ion-item>
</ion-list>
</ion-col>
</ion-row>
</ion-grid>
I'm not sure what you want.. If you need to display clicked item what you have to do is add (click) event where you call a function sending the item (Again, I don't know if you are asking this)...
<ion-item (click)="viewItem(val.prevention)"><h3>{{val.prevention}}</h3></ion-item>

Angular2, Ionic2 post to web service

import {Page, Platform} from 'ionic-angular';
import { Http, Headers, Response, RequestOptions, HTTP_PROVIDERS} from 'angular2/http';
import { bootstrap } from 'angular2/platform/browser';
import { Component, Injectable, Inject } from 'angular2/core';
import 'rxjs/Rx';
import { CORE_DIRECTIVES, FORM_DIRECTIVES } from 'angular2/common';
import {Observable} from 'rxjs/Observable';
#Page({
directives: [ CORE_DIRECTIVES, FORM_DIRECTIVES ],
templateUrl: 'build/pages/getting-started/getting-started.html'
})
#Injectable()
export class GettingStartedPage {
public platform;
public networkState;
private headers;
private _apiUrl = 'http://172.16.2.115:3004/message';
subject: string;
message: string;
comments: string;
constructor(platform: Platform, public http: Http) {
this.platform = platform;
this.headers = new Headers();
this.headers.append('Content-Type', 'application/x-www-form-urlencoded');
}
onSubmit(value) {
this.send(value.subject, value.body);
}
send(subject, body)
{
var message = "subject=" + subject + "&body=" + body;
let result = this.http.post(this._apiUrl,
body,
{
headers: this.headers
}).map(res => {
this.comments = res.json();
});
this.send(subject, body).subscribe(res => {
console.log(message);
console.log(this._apiUrl);
});
return result;
}
}
I am trying to create a mobile app using Ionic2 and Angular2 beta.This app will send an email using POST to a Rails web service. The Rails web service is working just fine. I dont seem to be getting to work the mobile app.
There was a misunderstanding
this.send(subject, body).subscribe(res => {
console.log(message);
console.log(this._apiUrl);
});
would be in a different method
onSubmit(value) {
this.send(value.subject, value.body)
.subscribe(res => {
console.log(message);
console.log(this._apiUrl);
});
}
send(subject, body)
{
var message = "subject=" + subject + "&body=" + body;
return this.http.post(this._apiUrl,
body,
{
headers: this.headers
}).map(res => {
this.comments = res.json();
});
}
You should refactor your code this way:
onSubmit(value) {
this.send(value.subject, value.body).subscribe(res => {
console.log(message);
console.log(this._apiUrl);
});
}
send(subject, body)
{
var message = "subject=" + subject + "&body=" + body;
let result = this.http.post(this._apiUrl,
body,
{
headers: this.headers
}).map(res => {
this.comments = res.json();
});
return result;
}