No response on database call (ionic3) - database

I try to get a value from a database. It is sensor data, which i want to save from an odroid on the database.
The problem is, I cannot get the value into my ionic 3 app.
The PHP file should work, when i open the file, i get the right number in the browser. for testing i also took just a .txt-file with the number 9 inside. but it still doesn´t work. It still stays empty. I have global variables into the provider, which i want to hold up-to-date.
Here is my code:
global.ts (provider)
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class GlobalProvider {
dif1:number;
constructor(public http: HttpClient){}
load() {
this.http.get("http://192.168.131.221/test/ultras.1.txt")
.subscribe((data : any) => {
this.dif1 = parseInt(JSON.stringify(data));
})
}
}
data.html (call of the provider)
<button ion-button (click)="global.load()">push</button>
<div class="llDataContainer">
<div class="llDataBox llDataBox-2"></div>
<div class="llDataBox llDataBox-2"></div>
<div class="llDataBox llDataBox-2">ultra1:</div>
<!--distance value (ultra1)-->
<div class="llDataBox llDataBox-2">{{ global.dif1 }} cm</div>
If i push the button, still it stays empty.

the good thing is that i get a response now. the bad thing: the response is NAN...
I tried this:
load() {
this.http.get('url').
toPromise().then(result => {
this.dif1 = parseInt(JSON.stringify(result));
})
}

Related

How can I run a function in a service, to get an API key before anything else?

I'm running ionic-angular framework working on an app that was started before me. I need to run a function in a service to get an API key from an external server before anything else. Because I want to check if a user has an API key and check if their stored GUID is valid by making another request to the server which I need the API key for. Because I'm going to check if they need to be routed to the login page or not. When I have a route guard checking if a user is logged in my API requests aren't completed or error out because I don't have an API key yet.
If I understood your problem you're asking this: you need to check "something" to decide if the user goes to the login page or goes to another screen, at the beginning of your app, when you open it. And that "something" consists in making http requests.
I will tell you how to do it, but in my experience if you need to make HTTP requests to decide to what screen redirect the user, you will get a blank page in the meanwhile. Depending on the connection 0.1s, 0.3s, 0.7s... But it's uggly. So the alternative would be to create a "Splash" screen with a loader circle, and use that page as the initial page. Then the page checks whatever and takes you to the next page.
Now, answering your question: you need a "CanActivate". CanActivate is guard (a code) that is executed before accessing a route, to check if you can access that page or redirect the user to another page. This is very useful for local checks (like checking the local storage) but as I said, http requests will cause a blank page for a small time. Follow these steps:
1 - First you need to create the CanActivate class. That's like creating a normal Service in ionic. Then make your service implement the CanActivate interface:
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Observable } form 'rxjs'; // Install 'npm i rxjs' if you don't have it!
#Injectable({
providedIn: 'root'
})
export class LoginGuard implements CanActivate { }
Then this service needs to implement a function called canActivate:
export class LoginGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : boolean|Observable<boolean> {
return new Observable<boolean>( observer => {
// HERE CHECK
if (!condition_to_avoid_login) {
// Complete the expected route, and enter the login
observer.next(true);
observer.complete();
}
else {
// Avoid login, go somewhere else:
observer.next(false);
this.router.navigate("/my-other-page");
observer.complete();
}
})
}
}
2 - You need to add this Guard to your route. In your routing file: app-routing.module.ts, add this guard to your page:
import { LoginGuard } from '...../login-guard.service';
const routes: Routes = [
...
{
path: 'login',
loadChildren: () => import('...../login.module').then( m => m.LoginPageModule),
canActivate: [LoginGuard]
}
...
]
Now everytime the user accesses this route (/login) the LoginGuard will trigger. There you decide if continue to the login page or redirect.

Showing a loading indicator while calling Apex in Salesforce LWC

What is the best way to show a loading indicator while retrieving data from Apex in a Lightning Web Component?
I have this approach:
import { LightningElement, api } from "lwc";
import shouldShowCard from "#salesforce/apex/ApexClass.shouldShowCard";
/**
* Card component that is conditionally shown based on Apex.
*/
export default class ConditionalCard extends LightningElement {
#api recordId;
#api isDone = false;
#api shouldShow = false;
connectedCallback() {
shouldShowCard({ id: this.recordId })
.then(result => {
this.shouldShow = result;
})
.finally(() => {
this.isDone = true;
});
}
}
And this HTML
<template>
<template if:false={isDone}>
<div>Loading...</div>
</template>
<template if:true={shouldShow>
<div>Card</div>
</template>
</template>
Now, this works but I'm using the LWC ESLint rules, and when I do this, I get an error/warning "no-api-reassignment" because I'm assigning the api properties in my connectedCallback.
https://github.com/salesforce/eslint-plugin-lwc/blob/master/docs/rules/no-api-reassignments.md
Which seems reasonable, though it very similar to the pattern that the Salesforce Lightning Spinner shows.
https://developer.salesforce.com/docs/component-library/bundle/lightning-spinner/documentation
So I'm just looking for advice on the best way to handle this or if I should just disable the ESLint rule. Other things to consider are how to test this stuff, the reactivity with the API decorator has made things pretty easy on my end but I don't want to continue if I'm not using the best approach.
You don't need #api if these parameters are internal state, if you don't plan to set them from parent component or expose them to System Administrator so he can configure the component in Lightning App Builder for example. You should be fine with just #track - or even no annotation at all. For simple variables you don't need #track since Spring'20 (release notes); you might still need it if your variable is array or object.
This should silence ESLint nicely.
I do it bit differently, personal preference back from Visualforce status and rendered days I guess.
<template>
<template if:true={loaded}>
<p>Content goes here</p>
</template>
<template if:false={loaded}>
<lightning-spinner variant="brand" alternative-text="Loading"></lightning-spinner>
</template>
</template>
import { LightningElement, api, wire, track } from 'lwc';
import someMethod from '#salesforce/apex/SomeClass.someMethod';
export default class StackExample extends LightningElement {
#api recordId;
#track data;
loaded = false;
#wire(someMethod, { i: '$recordId' }) wiredResponse({ error, data }) {
if (data) {
this.data = data;
// some post-processing here
} else if (error) {
// show toast?
}
if(data || error){
this.loaded = true;
}
}
}
Remember that some tags like <lightning-datatable> have internal spinner. Search the documentation for isLoading. So you could even not need the ifs in the html.

Meteor React tutorial interacting with mongo not working

I have been trying for a while to learn how to build mobile apps with Javascript, and honestly I have no idea how anyone is able to do anything. Everything is broken. Every tutorial I've tried has failed to work for some bizarre reason. I am at my wits end.
I've finally decided to try and be even simpler, and just do the most basic tutorial I can find. What could go wrong. Well, it only took 3 pages of almost no code to completely stop working. I've done this, and I cannot insert anything to my db. My app fetches no data. When trying to add a new task, it gets added then disappears almost immediately, with a message stating insert failed: Method '/tasks/insert' not found (not even an error with some traceback).
The code really couldn't be simpler:
// imports/api/tasks.js
import { Mongo } from 'meteor/mongo';
export const Tasks = new Mongo.Collection('tasks');
// imports/ui/App.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { withTracker } from 'meteor/react-meteor-data'
import { Tasks } from '../api/tasks.js';
import Task from './Task.js';
// App component - represents the whole app
class App extends Component {
handleSubmit(event) {
event.preventDefault();
// find the text field via the react ref
const text = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Tasks.insert({ text, createdAt: new Date() });
// Clear form
ReactDOM.findDOMNode(this.refs.textInput).value = '';
}
renderTasks() {
return this.props.tasks.map((task) => (
<Task key={task._id} task={task} />
));
}
render() {
return (
<div className="container">
<header>
<h1>Todo List</h1>
<form className="new-task" onSubmit={this.handleSubmit.bind(this)} >
<input
type="text"
ref="textInput"
placeholder="Type to add new tasks"
/>
</form>
</header>
<ul>
{this.renderTasks()}
</ul>
</div>
);
}
};
export default withTracker(() => {
return {
tasks: Tasks.find({}).fetch(),
};
})(App);
What is wrong? What am I missing?
The tutorial is indeed out of date and should be updated.
Background
In June 2017 there was a big security issue with allow/deny identified and the feature has been blocked since then.
Meteor allowed you to define client collection, that automatically synced with the server when the methods insert, update, remove were called on the client.
In order to control the access permissions, the allow/deny feature was implemented.
Now without allow/deny you will get the insert failed: Method '/tasks/insert' not found when classing SomeCollectionOnClient.insert but since this feature is obsolete (you will even get a big warning when setting it up), you need to create a server side method and call it from the client in order resolve this issue:
On the server create this method and ensure it is in the import chain from server/main.js:
new ValidatedMethod({
name: 'tasks.insert',
validate(args) {
// better use simpl-schema here
if (!args.text || !args.createdAt) {
throw new Meteor.Error('incompleteArgs', 'args are incomplete')
}
},
run (args) {
// check user permissions...
return Tasks.insert({ text, createdAt })
}
})
In your client component you can then call it via:
// find the text field via the react ref
const text = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
Meteor.call('tasks.insert', {text, createdAt: new Date()}, (err, res) => {
// do something on err / on res
})
Note that this couples your component to the server side method and you may rather try to implement some containers for your pages that handle all the connection / pub-sub / method calling activity wile your components solely render content.
More to read / used in this answer:
https://guide.meteor.com/react.html
https://guide.meteor.com/security.html
https://docs.meteor.com/api/methods.html#Meteor-call
https://guide.meteor.com/methods.html#validated-method

Property 'calendar' does not exist on type 'typeof client'

I'm trying to connect my Google Calender to my React website. I've got a component called Calendar. I've used the JS tutorial from Google and I've changed it to work in Typescript. I've got the authentication and authorization already working, however fetching data from the calendar is not working. I'm getting the following error when compiling/editing.
[ts] Property 'calendar' does not exist on type 'typeof client'. Did you mean 'calendars'?
I've already downloaded the types for the gapi.client.calendar and as you can see in the image below, they are also found in the #types folder. I'm kind of stuck and I don't know how I can fix this issue..
Here is my code from my Calendar.tsx
import * as React from 'react';
import { Button } from 'semantic-ui-react'
import googleApiKey from '../googleapi-key.json';
const CLIENT_ID = googleApiKey.CLIENT_ID;
const API_KEY = googleApiKey.API_KEY;
const DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
const SCOPES = "https://www.googleapis.com/auth/calendar.readonly";
class Calendar extends React.Component {
constructor(props: any) {
super(props);
console.log(CLIENT_ID);
console.log(API_KEY);
this.handleClientLoad = this.handleClientLoad.bind(this);
this.handleAuthClick = this.handleAuthClick.bind(this);
this.handleSignoutClick = this.handleSignoutClick.bind(this);
this.initClient = this.initClient.bind(this);
this.updateSigninStatus = this.updateSigninStatus.bind(this);
this.listUpcomingEvents = this.listUpcomingEvents.bind(this);
}
componentDidMount() {
this.initClient();
}
public render() {
return (
<div>
<Button onClick={this.handleAuthClick}>
authorizeButton
</Button>
<Button onClick={this.handleSignoutClick}>
signoutButton
</Button>
</div>
);
}
/**
* On load, called to load the auth2 library and API client library.
*/
public handleClientLoad() {
gapi.load('client:auth2', this.initClient);
}
/**
* Sign in the user upon button click.
*/
public handleAuthClick(event: any) {
gapi.auth2.getAuthInstance().signIn();
}
/**
* Sign out the user upon button click.
*/
public handleSignoutClick(event: any) {
gapi.auth2.getAuthInstance().signOut();
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
public async initClient() {
await gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
})
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(this.updateSigninStatus);
// Handle the initial sign-in state.
this.updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
}
/**
* Called when the signed in status changes, to update the UI
* appropriately. After a sign-in, the API is called.
*/
public updateSigninStatus(isSignedIn: any) {
if (isSignedIn) {
this.listUpcomingEvents();
}
}
/**
* Print the summary and start datetime/date of the next ten events in
* the authorized user's calendar. If no events are found an
* appropriate message is printed.
*/
public listUpcomingEvents() {
console.log(gapi.client.calendar); // <--- Compile error: Does not recognize calendar
}
}
export default Calendar;
EDIT
When performing console.log(gapi.client) I can see that the client contains a calendar object (see image). But why can't I reach it in my own code?
I managed to fix my own problem. After performing console.log(gapi.client) I noticed that calender was already there, so I tried the following gapi.client['calendar'] and it worked as it should. I don't know why Typescript does not recognize the calendar in the first place, so if anybody has an idea feel free to leave a comment.
Try the following
Install types npm i #types/gapi.client.calendar
Include https://apis.google.com/js/api.js & https://apis.google.com/js/platform.js in index.html
Add the following inside types in tsconfig.app.json
"types": [
"gapi",
"gapi.auth2",
"gapi.client",
"gapi.client.calendar"
]
You have to add:
"types": ["gapi", "gapi.auth2", "gapi.client", "gapi.client.calendar"]
in tsconfig.app.js and in tsconfig.json.

Can't connect react.js login to SpringBoot app

I am trying to call REST endpoints on one application (spring-boot) from another (reactjs). The applications are running on the following hosts and ports.
REST application, using spring boot, http://localhost:8080
HTML application, using reactjs, http://localhost:9000
I am trying to send the login info from reactjs to spring-boot but without success.
Reactjs:
import React from 'react';
export default class Login extends React.Component {
constructor() {
super();
this.state = {
login:"",
password:""
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState({login: this.state.login});
}
render() {
return (
<form role="form">
<div>
<input type="text" name="login" onChange={this.handleChange} />
<input type="password" name="password"/>
</div>
<button onClick={this.login.bind(this)}>Login</button>
</form>
);
}
login () {
var xmlhttp = new XMLHttpRequest(); // new HttpRequest instance
var url = "http://localhost:8080/test/login"
xmlhttp.open("POST", url );
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send(JSON.stringify({login: this.state.login}));
}
}
and Spring-boot:
#CrossOrigin(origins = "http://localhost:9000")
#RequestMapping(value = "/test/login")
public Boolean testLogin(#RequestParam String login) {
if ( login.equals ("ajt"))
return true;
else {
return false;
}
}
I can see that the two apps are connecting for even though reactjs gives me error 400, when I submit, the console of the Spring-boot app tells me:
Resolved exception caused by Handler execution: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'login' is not present
I can only assume that from the Spring-boot side, it cannot translate what ever is sent via react.js.
ps: bear with me, I have been coding for about 6 months.
I knew this looked familiar. Sorry my last answer didn't fix all your issues.
Your current problem is here;
public Boolean testLogin(#RequestParam String login) {
Should be
public Boolean testLogin(#RequestBody String login) {
EDIT:: Second problem.
Your handleChange function isn't taking in any values! It should look more like this;
handleChange(value) {
this.setState({login: value});
}
When your input field calls this function, it needs to pass a value from the input into the state. Your current code is essentially the same as this;
this.state.login = this.state.login;
Which obviously isn't going to get you anywhere.
Try that change. If it still does not work, be sure you open your dev-tools in your browser and step through the code line by line to be sure it is executing and storing the values you want it to.

Resources