Ionic app does not display anything - node.js

I have built a simple ionic app based on the following tutorial: Building a Review app with Ionic 2, MongoDB and Node by Josh Moroney. Whenever I execute the ionic serve command, the app runs in the browser, with no errors, but it displays nothing. Not even the UI elements of the app, just a plain blank screen.
Below are my codes - app.module.ts
import { NgModule } from '#angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { AddReviewPage } from '../pages/add-review/add-review'
import { ReviewsProvider } from '../providers/reviews/reviews';
#NgModule({
declarations: [
MyApp,
HomePage,
AddReviewPage
],
imports: [
IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
AddReviewPage
],
providers: [
ReviewsProvider
]
})
export class AppModule {}
Provider - reviews.ts
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
/*
Generated class for the ReviewsProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
#Injectable()
export class ReviewsProvider {
data: any;
constructor(public http: HttpClient) {
this.data = null;
}
getReviews(){
if (this.data) {
return Promise.resolve(this.data);
}
return new Promise(resolve => {
this.http.get('http://localhost:8080/api/reviews')
.map(res => res)
.subscribe(data => {
this.data = data;
resolve(this.data);
});
});
}
createReview(review){
let headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
this.http.post('http://localhost:8080/api/reviews', JSON.stringify(review), {headers: headers})
.subscribe(res =>
console.log(res));
}
deleteReview(id){
this.http.delete('http://localhost:8080/api/reviews/' + id).subscribe((res) =>
console.log(res));
}
}
Pages -> add-review.html
<ion-header>
<ion-toolbar transparent>
<ion-title>Add Review</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="close()"><ion-icon name="close"></ion-icon></button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list no-lines>
<ion-item>
<ion-label floating>Title</ion-label>
<ion-input [(ngModel)]="title" type="text"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Review</ion-label>
<ion-textarea [(ngModel)]="description"></ion-textarea>
</ion-item>
<ion-item>
<ion-range min="0" max="100" pin="true" [(ngModel)]="rating">
<ion-icon range-left name="sad"></ion-icon>
<ion-icon range-right name="happy"></ion-icon>
</ion-range>
</ion-item>
</ion-list>
<button ion-button full color="secondary" (click)="save()">Save</button>
</ion-content>
add-review.ts
import { Component } from '#angular/core';
import { ViewController } from 'ionic-angular';
/**
* Generated class for the AddReviewPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-add-review',
templateUrl: 'add-review.html',
})
export class AddReviewPage {
title: any;
description: any;
rating: any;
constructor(public viewCtrl: ViewController) {
}
save(): void {
let review = {
title: this.title,
description: this.description,
rating: this.rating
};
this.viewCtrl.dismiss(review);
}
close(): void {
this.viewCtrl.dismiss();
}
ionViewDidLoad() {
console.log('ionViewDidLoad AddReviewPage');
}
}
Home page -> home.html
<ion-header>
<ion-navbar transparent>
<ion-title>
Review King
</ion-title>
<ion-buttons end>
<button ion-button icon-only (click)="addReview()"><ion-icon name="add"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list no-lines>
<ion-item-sliding *ngFor="let review of reviews">
<ion-item>
<ion-avatar item-left>
<img src="https://api.adorable.io/avatars/75/{{review.title}}">
</ion-avatar>
<h2>{{review.title}}</h2>
<p>{{review.description}}</p>
<ion-icon *ngIf="review.rating < 50" danger name="sad"></ion-icon>
<ion-icon *ngIf="review.rating >= 50" secondary name="happy"></ion-icon>
{{review.rating}}
</ion-item>
<ion-item-options>
<button ion-button color="danger" (click)="deleteReview(review)">
<ion-icon name="trash"></ion-icon>
Delete
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-content>
home.ts
import { Component } from '#angular/core';
import { NavController, ModalController } from 'ionic-angular';
import { AddReviewPage } from '../add-review/add-review';
import { ReviewsProvider } from '../../providers/reviews/reviews';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
reviews : any;
constructor(public navCtrl: NavController, public reviewService: ReviewsProvider, public modalCtrl: ModalController) {
}
ionViewDidLoad(){
this.reviewService.getReviews().then((data) => {
console.log(data);
this.reviews = data;
});
}
addReview(){
let modal = this.modalCtrl.create(AddReviewPage);
modal.onDidDismiss(review => {
if(review){
this.reviews.push(review);
this.reviewService.createReview(review);
}
});
modal.present();
}
deleteReview(review){
//Remove locally
let index = this.reviews.indexOf(review);
if(index > -1){
this.reviews.splice(index, 1);
}
//Remove from database
this.reviewService.deleteReview(review._id);
}
}
I was unable to figure out what I had been doing wrong. Can anyone please point it out? Is it a problem with my view pages, or the configuration in app.module.ts?

Please ensure that there is a rootPage set in your app.component.ts page.
If not, insert the following into the class
rootPage: any = HomePage;

Related

Failed to compile ./src/App.js Line 30:3: 'onInputChange' is not defined no-undef

Failed to compile
./src/App.js
Line 30:3: 'onInputChange' is not defined no-undef
Search for the keywords to learn more about each error.
This error occurred during the build time and cannot be dismissed.
The code of App.js
import React from 'react';
import Logo from './components/Logo/Logo';
import './App.css';
import Navigation from './components/Navigation/Navigation';
import ImageLinkForm from './components/imagelink/ImageLinkForm';
import Rank from './components/Rank/rank'
import Particles from 'react-particles-js';
const particlesOptions= {
particles: {
number:{
value:30,
density:{
enable:true,
value_area:800
}
}
}
}
function App() {
constructor()
{
super();
this.state = {
input: '',
}
}
onInputChange = (event) => {
console.log(event.target.value);
}
return (
<div className="App">
<Particles className="particles"
params={particlesOptions} />
<Navigation/>
<Logo/>
<Rank/>
<ImageLinkForm onInputChange={this.onInputChange}/>
{/*<FaceRecognition/>*/}
</div>
);
}
export default App;
The code of ImageLinkForm.js
import React from 'react';
import './ImageLinkForm.css';
const ImageLinkForm = ({ onInputChange }) => {
return (
<div>
<p className='f3'>
{'This Magic Brain will detect faces in your pictures'}
</p>
<div className='center'>
<div className='form center pa4 br3 shadow-5'>
<input className='f4 pa2 w-70 center' type='tex' onChange={onInputChange}/>
<button className='w-30 grow f4 link pv2 dib white bg-light-purple'>Detect</button>
</div>
</div>
</div>
);
}
export default ImageLinkForm;
I want to know how to fix this error.
I solved it.
By writing a class on it.
App.js
import React, { Component } from 'react';
import Logo from './components/Logo/Logo';
import './App.css';
import Navigation from './components/Navigation/Navigation';
import ImageLinkForm from './components/imagelink/ImageLinkForm';
import Rank from './components/Rank/rank'
import Particles from 'react-particles-js';
const particlesOptions= {
particles: {
number:{
value:30,
density:{
enable:true,
value_area:800
}
}
}
}
class App extends Component
{
constructor()
{
super();
this.state = {
input: '',
}
}
onInputChange = (event) => {
console.log(event.target.value);
}
render(){
return (
<div className="App">
<Particles className="particles"
params={particlesOptions} />
<Navigation/>
<Logo/>
<Rank/>
<ImageLinkForm onInputChange={this.onInputChange}/>
{/*<FaceRecognition/>*/}
</div>
);
}
}
export default App;

How to render HTML from a prop coming from MongoDB

I can't make my prop render in HTML. I'm making an app for a Christian ministry and I want to be able to post like a blog, I got quill working but I can't show the results rendered, is showing pure HTML.
I'v been trying to follow the rules of react-render-html, but my experience is little, so I don't really know what I'm missing. I try use 'renderHTML' but it doesn't work.
Below is my code, and if you see the screenshot, you will see that the first card is showing the HTML tags.
import React from 'react';
import { Container, Card, Button, CardTitle, CardText, CardColumns, CardSubtitle, CardBody, Collapse } from 'reactstrap';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import { connect } from 'react-redux';
import { getPosts, deletePost } from '../actions/postActions';
import PropTypes from 'prop-types';
import axios from 'axios';
import renderHTML from 'react-render-html';
import PostsForm from './extentions/PostsForm';
class Home extends React.Component {
componentDidMount() {
this.props.getPosts();
}
onDeleteClick = (id) => {
this.props.deletePost(id);
}
constructor(props) {
super(props);
this.onEntering = this.onEntering.bind(this);
this.onEntered = this.onEntered.bind(this);
this.onExiting = this.onExiting.bind(this);
this.onExited = this.onExited.bind(this);
this.toggle = this.toggle.bind(this);
this.state = {
collapse: false,
status: 'Closed',
ButtonText: "Submit Post"
};
}
onEntering() {
this.setState({ status: 'Opening...' });
}
onEntered() {
this.setState({ status: 'Opened' });
}
onExiting() {
this.setState({ status: 'Closing...' });
}
onExited() {
this.setState({ status: 'Closed', ButtonText: "Submit Post" });
}
toggle() {
this.setState(state => ({ collapse: !state.collapse, ButtonText: "Close" }));
}
formOpening = () => {
this.setState({
on: !this.state.on
})
}
render(){
const { posts } = this.props.post;
return(
<Container>
<div style={{float: "left"}}><h5>Current state: {this.state.status}</h5></div>
<div style={{float: "right"}}><Button
color="dark"
style={{marginButtom: '2rem'}}
onClick={this.toggle}>{this.state.ButtonText}</Button></div>
<Collapse
isOpen={this.state.collapse}
onEntering={this.onEntering}
onEntered={this.onEntered}
onExiting={this.onExiting}
onExited={this.onExited}
style={{clear: "both"}}
>
<Card>
<CardBody>
<PostsForm />
</CardBody>
</Card>
</Collapse>
<CardColumns style={{clear: "both"}}>
<TransitionGroup className="Posts">
{posts.map(({ _id, title, subtitle, postbody}) => (
<CSSTransition key={_id} timeout={500} classNames="fade">
<Card>
<CardBody>
<Button className="remove-btn" color="danger" size="sm" onClick={this.onDeleteClick.bind(this, _id)}>×</Button>
<CardTitle><h3>{title}</h3></CardTitle>
<CardSubtitle><h4>{subtitle}</h4></CardSubtitle>
<CardText>{postbody}</CardText>
<Button>Read More</Button>
</CardBody>
</Card>
</CSSTransition>
))}
</TransitionGroup>
</CardColumns>
</Container>
)
}
};
Home.propTypes = {
getPosts: PropTypes.func.isRequired,
post: PropTypes.object.isRequired
}
const mapStateToProps = (state) => ({
post: state.post
});
export default connect(mapStateToProps, { getPosts, deletePost })(Home);
Screenshot of how it looks now
I would like to see that the cards are acting like
Body Text ect etc etc not <p>Body Text ect etc etc</p>
You need to use dangerouslySetInnerHTML API.
From React Docs, slightly modified:
function createMarkup(html) {
return {__html: html};
}
function MyComponent({html}) {
return <div dangerouslySetInnerHTML={createMarkup(html)} />;
}
https://reactjs.org/docs/dom-elements.html

Ionic 4 - Camera - Runtime Error - Object(...) is not a function

I'm creating an Ionic app with camera function. I used for this the doc from ionic-framework Ionic native camera
But I get an error when I tried to display the app on my Android device and click onto the "Take a Picture" button.
Error
"Runtime Error Object(…) is not a function"
"TypeError: Object(…) is not a function at Camera.getPicture"
home.ts
import { Component } from '#angular/core';
import { NavController, PopoverController, ViewController } from 'ionic-angular';
import { UserServiceProvider } from './../../providers/user-service/user-service';
import { Camera, CameraOptions, DestinationType, EncodingType, MediaType } from '#ionic-native/camera/ngx';
#Component({
selector: 'page-home',
templateUrl: 'home.html',
})
export class HomePage {
constructor(public navCtrl: NavController, public popoverCtrl: PopoverController, private camera:Camera) {}
myPhoto:any=''
takePicture(){
const options: CameraOptions = {
quality:100,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
this.camera.getPicture(options).then((imageData)=>{
this.myPhoto=(<any>window).Ionic.WebView.convertFileSrc(imageData);
}, (err) => {
// Error log
});
}
openMoreSetting(event) {
let popover = this.popoverCtrl.create(PopoverPage);
popover.present({
ev: event
});
}
}
#Component({
template: `
<ion-list>
<button ion-item>Menu für Settings</button>
</ion-list>
`
})
export class PopoverPage {
constructor(private userServiceProvider: UserServiceProvider,
private viewCtrl: ViewController) {
}
close() {
this.viewCtrl.dismiss();
}
}

How to send events from nodeJS/express to angular

I have a long running transaction, and I would like to inform the client of the progress. My front end is Angular 4 and backend is nodeJS/Express . The client initiates the transaction via HTTP Post .
Angular does provide a facility to listen to event progress . https://angular.io/guide/http#listening-to-progress-events
My question is, how can I send events from my express App to Angular app?
As of the moment I don't want to use sockets.io .
Listening to upload progress events is actually a client-side feature. What it does behind the scenes is that it tells you the progress based on how much data the client i.e. the browser, has sent to the server. It doesn't actually get a response from the server (as I assume what you are thinking) for how much data the server has received and then displaying the progress to the user. So, if you would think logically and technically, it can not help you in any way. Also, as far as my knowledge goes, sockets are the only way to get a real-time update of the things happening on the server side.
Based on Angular's documentation, progress events can be handled by client, and after doing some searching I cam across server side events - SSE, which is basically sending response headers with connection alive header, and then progress data .
I was able to do it, but I still have issues sending and handling custom user events per angular. Here is what that I have.
App component.ts
import { Component ,OnInit} from '#angular/core';
import { CommonService} from './common.service';
import { Observable,Subscription } from "rxjs/Rx";
import 'rxjs/add/operator/timeout';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css','../../node_modules/bootstrap/dist/css/bootstrap-
theme.min.css']
})
export class AppComponent implements OnInit {
private sseStream: Subscription;
messages:Array<string> = [];
progress:number=0;
totalProgress:number=7;
constructor(private commonService: CommonService ) { }
ngOnInit(){
this.commonService.getHttpObj().subscribe(event=>{
if(event){
if(event['loaded']){
console.log(event['loaded']);
this.progress=(event['loaded'] / this.totalProgress)*100;
}
}
});
}
title = 'Angular4';
}
common.service.ts
import { Injectable } from '#angular/core';
import {HttpRequest} from '#angular/common/http';
import { Observable } from "rxjs/Rx";
import { catchError, map, tap , last} from 'rxjs/operators';
import { HttpClient } from '#angular/common/http';
import { HttpEventType } from '#angular/common/http';
const req = new HttpRequest('GET', 'http://localhost:9080/event', {
reportProgress: true
});
#Injectable()
export class CommonService {
constructor(private http: HttpClient) { }
getHttpObj(){
return this.http.request(req).pipe(
map(event => this.getEventMessage(event)),
tap(message => this.showProgress(message)),
// last(), // return last (completed) message to caller
// catchError(this.handleError())
);
};
private getEventMessage(event: any) {
switch (event.type) {
// case HttpEventType.Sent:
// return `Uploading file `;
case HttpEventType.UploadProgress:
// Compute and show the % done:
const percentDone = Math.round(100 * event.loaded / event.total);
return `File is ${percentDone}% uploaded.`;
case HttpEventType.Response:
return `Complete`;
case HttpEventType.User:
return event;
case HttpEventType.UploadProgress:
return `${JSON.stringify(event)}`;
case HttpEventType.DownloadProgress:
return event;
default:
return event;
}
}
showProgress(a:any){
//console.log(a);
return a;
}
private handleError<T> () {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
// console.error('error'); // log to console instead
// TODO: better job of transforming error for user consumption
// console.log(`${error.message}`);
// Let the app keep running by returning an empty result.
return null;
};
}
}
app.component.html
`<div class="container">
<div style="text-align:center">
<h1>
Welcome to {{title}}!!
</h1>
<input type="text" [(ngModel)]="test">
<p>{{test}}</p>
</div>
<div class="progress">
<div class="progress-bar bg-success" [ngStyle]="{'width':progress + '%'}"></div>
</div>
</div> `
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms'
import { AppComponent } from './app.component';
import { ServerComponent } from './server/server.component';
import { ServersComponent } from './servers/servers.component';
import { HttpClientModule } from '#angular/common/http';
import {CommonService } from './common.service';
import { HttpModule } from '#angular/http';
#NgModule({
declarations: [
AppComponent,
ServerComponent,
ServersComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
HttpModule
],
providers: [CommonService],
bootstrap: [AppComponent]
})
export class AppModule { }
server.js
var express=require('express');
var app=express();
app.listen(9080);
app.get('/event',(req,res)=>{
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write("\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
setTimeout(() => {
res.write( "\n") ;
res.write(JSON.stringify({})) ;
res.end();
},
2000);
},
2000);
},
2000);
},
2000);
},
2000);
[enter image description here][1]});

ag-grid in jhipster angular 4

i'm trying to use ag-grid in a jhipster project. After adding ag-grid to my project, I imported the module in app.module:
{AgGridModule} from 'ag-grid-angular';
i modified the component in order to use ag-grid:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { Subscription } from 'rxjs/Rx';
import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster';
import { Typapp } from './typapp.model';
import { TypappService } from './typapp.service';
import { ITEMS_PER_PAGE, Principal, ResponseWrapper } from '../../shared';
import {ColDef, ColumnApi, GridApi} from 'ag-grid';
#Component({
selector: 'jhi-typapp',
templateUrl: './typapp.component.html'
})
export class TypappComponent implements OnInit, OnDestroy {
typapps: Typapp[];
typs: Typapp[]
currentAccount: any;
eventSubscriber: Subscription;
/**
* Declarations AG-GRID
*/
// rowdata and column definitions
rowData: Typapp[];
columnDefs: ColDef[];
// gridApi and columnApi
api: GridApi;
columnApi: ColumnApi;
constructor(
private typappService: TypappService,
private jhiAlertService: JhiAlertService,
private eventManager: JhiEventManager,
private principal: Principal
) {
this.columnDefs = this.createColumnDefs();
}
loadAll() {
this.typappService.query().subscribe(
(res: ResponseWrapper) => {
this.typapps = res.json;
},
(res: ResponseWrapper) => this.onError(res.json)
);
}
ngOnInit() {
this.loadAll();
this.principal.identity().then((account) => {
this.currentAccount = account;
});
this.registerChangeInTypapps();
/**
* modif component aggrid
*/
this.typappService.findAll().subscribe(
(rowData) => {
this.rowData = rowData
},
(error) => {
console.log(error);
}
)
}
ngOnDestroy() {
this.eventManager.destroy(this.eventSubscriber);
}
trackId(index: number, item: Typapp) {
return item.id;
}
registerChangeInTypapps() {
this.eventSubscriber = this.eventManager.subscribe('typappListModification', (response) => this.loadAll());
}
private onError(error) {
this.jhiAlertService.error(error.message, null, null);
}
/**
* AG GRID fonctions
*/
// one grid initialisation, grap the APIs and auto resize the columns to fit the available space
onGridReady(params): void {
this.api = params.api;
this.columnApi = params.columnApi;
this.api.sizeColumnsToFit();
}
// create some simple column definitions
private createColumnDefs() {
return [
{field: 'id'},
{field: 'libTyp'},
]
}
}
there is the code of component.html
<h6> without AGRID</h6>
<div *ngFor="let rd of rowData">
<span>{{rd.id}}</span>
<span>{{rd.libTyp}}</span>
</div>
<br/>
<h6> with AGRID</h6>
<ag-grid-angular style="width: 100%; height: 800px;"
class="ag-theme-fresh"
(gridReady)="onGridReady($event)"
[columnDefs]="columnDefs"
[rowData]="rowData">
</ag-grid-angular>
and this is the result:
What i'm doing wrong? why there is no results when i use ag-grid?
Even in the console there is no error.
Thank you very much.
I had the same issue. Did you import ag-theme-fresh.css to vendor.css? This did the trick for me.
\src\main\webapp\content\css\vendor.css:
...
#import '~ag-grid/dist/styles/ag-theme-fresh.css';

Resources