Angular2 API call return nothing - node.js

My problem is, that it isn't displayed in html form. How can I solve this ?
The query is well, and I get the result on URL, but can't display it on component.html.
( It works and I see if I call the URL /api/mainstorage so it display me the JSON content.)
Index.js
var express = require('express');
var router = express.Router();
// http://localhost:3000/
router.get('/', function(req, res, next) {
res.status(200)
.json({
status: 'success',
message: 'Live long and prosper!'
});
});
var db = require('./queries');
router.get('/api/mainstorage', db.getAllDocuments);
module.exports = router;
Queries.js
var promise = require('bluebird');
var options = {
// Initialization Options
promiseLib: promise
};
var pgp = require('pg-promise')(options);
var connectionString ='postgres://dbuser:Storage#localhost/mainstorage'
var db = pgp(connectionString);
const axios = require('axios');
const API = 'http://localhost:3000';
function getAllDocuments(req, res, next) {
axios.get(`${API}/main`)
db.any('SELECT * FROM files')
.then(function (data) {
res.status(200)
.json({
status: 'success',
data: data,
message: 'Retrieved all files'
});
})
.then(documents => {
res.send(200).json();
})
.catch(function (err) {
return next(err);
});
}
module.exports = {
getAllDocuments: getAllDocuments
};
documents.component.ts
export class DocumentsComponent implements OnInit {
title = 'app works!';
mainstorage;
documents: any [];
constructor(private documentsService: DocumentsService) { }
ngOnInit() {
// Retrieve documents from the API
this.documentsService.getAllDocuments().subscribe(documents => {
this.documents = documents;
});
}
}
documents.service.ts
#Injectable()
export class DocumentsService {
constructor(private http: Http) {}
getAllDocuments(){
return this.http.get('/api/mainstorage')
.map(res => res.json());
}
}
documents.component.html
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>

You are not able to see anything in the html because service data is asynchronous and you are trying to display it before the service returns it back.
You can solve this by wrapping your variables in *ngIf
<div *ngIf='documnets'>
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>
</div>
</div>
</div>
*ngIf will check if there are documents and once data from service is received it will be displayed.

Related

How to send file in form data in Next Js?

I have created an API in Node js for file upload. It is working fine with the postman.
I made a form for uploading Excel files in Next Js. I can able to see selected files in the console.
But I am not able to set the file in formdata. I am getting empty form data in the console.
<div>
<input
class="form-control w-25"
multiple={false}
type="file"
id="ExcelFile"
onChange={uploadFile}
required
></input>
{/* </label> */}
<button
type="button"
// disabled={!selectedImage}
class="btn btn-primary "
>
ADD SOLUTION
</button>
</div>
const uploadFile = ({ target: { files } }) => {
console.log(files[0]);
// let data = new formData();
let FilesData = new FormData();
FilesData.append("excel_file", files[0]);
console.log("Files in multipart");
console.log(FilesData);
// data.append("file", files[0]);
};
https://codesandbox.io/embed/next-js-forked-th22n?fontsize=14&hidenavigation=1&theme=dark
If you try to console.log FormData object, you will just get empty object.Instead you should call the entries method on the FormData object.
for (const pair of FilesData.entries()){
console.log(pair)
}
It will return list of arrays of key-value pairs.
Notice that you can`t see your formData in console.log
If you want to pass data with formData you must use one middleware in your server like this: https://nextjs.org/docs/api-routes/api-middlewares
And i just use one example maybe be usefull:
in your formData:
var FormData = require("form-data");
let data = new FormData()
data.append("urlOrContent", urlOrContent)
and then send your formData in your server side
in your server side:
import middleware from "./middleware/middleware";
import nextConnect from "next-connect";
const handler = nextConnect();
handler.use(middleware);
handler.post(async (req, res) => {
//in formData: req.body.urlOrcontent[0]
try {
const response = await fetch(
req.body?.urlOrContent[0],
);
res.status(200).send({
data: {
message: "Success",
data: response.json(),
},
});
} catch (err) {
let e = {
func: "states.handler",
message: "خطای داخلی سرور رخ داده است!",
error: "Internal Server Error!",
code: 500,
};
res.status(500).json(e);
}
});
export const config = {
api: {
bodyParser: false,
},
};
export default handler;
Here's a little example on a simple form submission in next.js using multer to parse the form data.
Client
This is the client page, containing a super simple HTML form (can work without JS too)
// pages/my-form.ts
export default function Page() {
return (
<div>
<form id="data" method="post" action='/api/on-form-submit' encType="multipart/form-data">
<input name="title" label="Title"/>
<input name="video" label="Video"/>
<button type="submit">Submit</button>
</form>
</div>
);
};
Server
This is the server function that will receive the form submission.
// pages/api/on-form-submit.ts
import multer from "multer";
import { NextApiRequest, NextApiResponse } from "next";
async function parseFormData(
req: NextApiRequest & { files?: any },
res: NextApiResponse
) {
const storage = multer.memoryStorage();
const multerUpload = multer({ storage });
const multerFiles = multerUpload.any();
await new Promise((resolve, reject) => {
multerFiles(req as any, res as any, (result: any) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
return {
fields: req.body,
files: req.files
}
}
// IMPORTANT: Prevents next from trying to parse the form
export const config = {
api: {
bodyParser: false,
},
};
const Handler: NextApiHandler = async (req, res) => {
const result = await parseFormData(req, res);
console.log(result);
res.status(200).redirect('/success-page');
}
export default Handler;

How do I use data from POST request for the next GET request

I'm trying to build a web app that uses Spotify API now. I want it to send a search keyword that an user submits to the server and send back its search result to the front end. The problem is I get a 404 status code for the fetch call. The POST request works fine.
Main.js
import React, { Component } from "react";
import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
axios
.post(
"http://localhost:4000/search_result",
{
keyword: this.state.keyword,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
}
componentDidMount() {
fetch("http://localhost:4000/api")
.then((res) => res.json)
.then((artists) => {
this.setState({ artists });
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map((elem) => (
<SingerCard
images={elem.images}
name={elem.name}
artists={this.state.artists}
/>
))}
{console.log(this.state.artists)}
</div>
<br />
</div>
);
}
}
export default Main;
server.js
const express = require("express");
const SpotifyWebApi = require("spotify-web-api-node");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const port = 4000 || process.env.PORT;
require("dotenv").config();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
function (data) {
console.log("The access token expires in " + data.body["expires_in"]);
console.log("The access token is " + data.body["access_token"]);
// Save the access token so that it's used in future calls
spotifyApi.setAccessToken(data.body["access_token"]);
},
function (err) {
console.log("Something went wrong when retrieving an access token", err);
}
);
app.post("/search_result", (req, res) => {
console.log(req.body.keyword);
spotifyApi.searchArtists(req.body.keyword).then(function (data) {
var search_res = data.body.artists.items;
res.json(search_res);
app.get("http://localhost:/api", (req, res) => {
res.json(search_res);
res.end();
});
res.end();
}),
function (err) {
console.log(err);
};
});
app.listen(port, () => console.log(`It's running on port ${port}`));
I think the app.get() in the app.post() causes the error but I can't figure out another way to send the search result back.
You're getting a 404 because the get method is not correctly defined.
Update your server code to define the get method to just keep the pathname, like this:
app.get("/api", (req, res) => {
// ...
}
Currently, you are defining this route inside the app.post. The get route definition should be outside of the post route.
Use Axios.get
import React, { Component } from "react";
// import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
};
axios.post(
"https://jsonplaceholder.typicode.com/users",
{ keyword: this.state.keyword },
{ headers: headers }
)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
this.setState({
artists: res.data
});
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map(elem => (
<div key={elem.id}>
<ul>
<li>{elem.name}</li>
</ul>
</div>
))}
</div>
</div>
);
}
}
export default Main;

NodeJS render html file with form not working on angular side

I am using ExpressJS with EJS template view engine. I am trying to show an HTML file on the angular component, but the form tag and its child input tag do not work on the angular side. They show only label data.
On NodeJS
agreementController.js
exports.getAgreementHtml = async (request, response, next) => {
const params = request.query
let reqPath = path.join(__dirname, '../agreements');
var agreementObj = {
user: { email: "example#gmail.com" }
}
// render domestic rent html
ejs.renderFile(reqPath + '/domestic_rent.ejs', agreementObj, {}, function (err, str) {
if (err !== null) {
responseObj.status = errorCodes.DATA_NOT_FOUND
responseObj.message = language.getMessage('NO_RECORD_FOUND')
response.send(responseObj)
return
}
responseObj.status = errorCodes.OK
responseObj.data = str
response.send(responseObj);
return;
});
}
domestic_rent.js
<form>
<div class="form-group">
<p><%= user.email %></p>
<div class="col-sm-offset-2 col-sm-10">
<input type="text" class="form-control" id="inputEmail3" placeholder="test" required name="test">
</div>
</div>
</form>
On Angular 8 Side
agreement-show.component.ts
getAgreementData() {
const params = {
id: this.agreementId
};
this.agreementService.getAgreementHtml(params).subscribe(
(result) => {
console.log('result agreement data::: ', result);
if (result.status !== 200) {
this.commonService.change.emit({ status: 'error', message: 'unknown error' });
return;
}
this.someHtml = result.data;
return;
}, (error) => {
console.log('error', error)
this.commonService.change.emit({ status: 'error', message: error.message });
}
);
}
agreement-show.component.html
<div [innerHTML]="someHtml"></div>
Output Attachment
By using ElementRef function we can add html runtime.
Please use following step:
#ViewChild('showitems') showitems: ElementRef;
const elemt: HTMLElement = this.showitems.nativeElement;
this.someHtml = result.data;
elemt.innerHTML = this.someHtml;

How to parse json response using fetch API

Am trying to display json response after calling an API using fetch, I can see the response in the response tab of chrome, but I can't find it in fetch response object
Client side
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
query: '',
properties: []
}
this.search = this.search.bind(this);
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
const { name, value } = event.target;
// const { query } = this.state.query;
this.setState({
[name]: value
});
}
search() {
console.log('fetching data')
try {
fetch('http://localhost:3000/property/find', {
method: 'POST',
mode: 'CORS',
body: JSON.stringify({ "query": this.state.query }),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json())
.then((data) => {
console.log(data)
this.setState({ properties: data.result });
})
}
catch (err) {
return err;
}
}
render() {
const { properties } = this.state;
return (
<div className="App" >
<input type="text" name="query" onChange={this.handleChange}></input>
<div className="form-group">
<button className="btn btn-primary" onClick={this.search}>Search</button>
</div>
<div className="row text-center">
{properties.items &&
properties.items.map((property, index) =>
<div className="col-lg-3 col-md-6 mb-4" key={index}>
<div className="card h-100">
<img className="card-img-top" src="http://placehold.it/500x325" alt="" />
<div className="card-body">
<h4 className="card-title"> {property.details.description}</h4>
{/* <p className="card-text">{property.biography}</p> */}
</div>
<div className="card-footer">
Find Out More!
</div>
</div>
</div>
)
}
</div>
</div>
)
}
}
export default App;
Server side
var app = express();
const server = http.createServer(app);
const io = socketIo(server);
var db = require('./db');
var property = require('./endpoint/property');
// var authController = require('./auth/AuthController');
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
next();
});
//allow OPTIONS on just one resource
// app.post('*', cors())
app.use(cors())
app.use('/property', property);
End point response
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({ extended: true }));
router.use(bodyParser.json());
var Model = require('../model/propertyModel');
// GETS A SINGLE USER FROM THE DATABASE
router.post('/find',function (req, res) {
var query = req.body.query
console.log(query)
Model.find( { $text: { $search: query }} , { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } ).then((data)=>{
if(data.length>0){
res.status(200).json({"result":data});
}
if (data.length==0){
Model.find({ "details.description": {$regex:query} }).sort( { score: { $meta: "textScore" } } ).then((data)=>{
if(data){
res.status(200).json({"result":data});
}
if (data.length==0) return res.status(404).send("No properties found.");
})
}
})
});
Inside your render method, if you change this:
{properties.items &&
properties.items.map((property, index) =>
...to this:
{properties &&
properties.map((property, index) =>
That should resolve this for you.
Within the render method, it looks like properties.items is expected to be an array. But in the network tab response screenshot, the result field inside the JSON response is an array.
Calling this.setState({ properties: data.result }); will lead to properties being the field you should be mapping over in the render method, instead of properties.items

Displaying API calls from nodeJS inside reactJS component

so I'm making an app where I had to create a nodeJS server and I have to display the API calls on the client side(reactJS). However, when I call the fetch() method, nothing gets displayed on the client side but only on the server side in my terminal. I probably don't know how to do it properly, so I was just wondering if any of you guys have an idea of what I'm doing wrong, I just want to learn, that's all. Here's small part of my server side:
const express = require('express');
const router = express.Router();
var key = "v2xcfdfa76db9f173028d97859c47a8ce0554321029a3fbfc06a26f81b1655bd3d9";
var BitGo = require('bitgo');
var client = new BitGo.BitGo({ env: 'test', accessToken: key });
router.get('/user/me', (req, res, next) => {
client.me({}, function callback(err, user) {
if (err) {
console.dir(err);
}
console.dir(user);
});
});
module.exports = router;
And here's the client side:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: ""
}
}
componentDidMount() {
return fetch('/user/me')
.then((response)=> response.json())
.then((responseJson)=>{
this.setState({
data: responseJson.data
});
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Data from our API: <b>{this.state.data}</b>
</p>
</div>
);
}
}
export default App;
You aren't actually returning anything from the server... or so it seems with the limited code you gave us.
router.get('/user/me', (req, res, next) => {
client.me({}, function callback(err, user) {
if (err) {
console.dir(err);
res.status(400).send(err)
}
console.dir(user);
res.send({ data: user })
});
});
I'm assuming that user is JSON serializable (and that it's the data that you want returned from the server).

Resources