Il recupero dei dati da MongoDB provoca l'errore "Impossibile leggere la proprietà 'nome' di null""
Ho cercato di restituire alcune informazioni sugli utenti e di visualizzarle tramite HTML. Ma ricevo l'errore: "Impossibile leggere la proprietà 'nome' di null" errore "Per memorizzare i dati sto usando MongoDB, per il servizio di backend Express e Node.js e per il frontend Angular. Per comunicare tra back e frontend ho delegato quello a HttpClient.La connessione con Mongo funziona bene poiché la mia console riceve tutti i dati ma quando si tratta del lato frontend mi sta dando questo problema.
metodo di classe route-index.js per la connessione con MongoDB
router.get('/tasks', async (req, res) => {
let MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
res.json([
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('angular-auth');
dbo.collection('users').find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
//db.close;
});
})
])
});
Tasks.service.ts metodo di classe per la restituzione dei dati al frontend
getTasks() {
return this.httpClient.get<any>(this.URL + '/tasks');
}
private-tasks.component.ts class ngOnInit() metodo che suppone di ottenere e sottoscrivere i dati
ngOnInit(): void {
this.tasksService.getTasks()
.subscribe(
res => {
console.log(res); //<===== this line is returning null value!
this.tasks = res;
},
err => console.log(err)
);
}
classe private-tasks.component.html
<ul class="list-group">
<li class="list-group-item" *ngFor='let task of tasks'>
{{task.firstname}}
</li>
</ul>
console.log(res); fornisce un valore nullo, ma all'interno dell'istruzione if/else in realtà non è nullo ... Come sono sicuro che non lo sia ... perché lo stesso metodo mi sta dando l'output nella console. ho provato anche ad aggiungere ? a {{task?.firstname}} in questo modo non ricevo alcun errore ma ancora console.log(res); dà valore nullo.
C'è qualcosa che puoi suggerire su come affrontare questo problema?
Risposte
Il colpevole è la res.json
chiamata sul lato back-end. Il lato front-end del codice sembra buono. L'argomento della chiamata di funzione dovrebbe essere un oggetto che restituisci dal server al client, ma cosa gli stai dando invece se qualunque MongoClient.connect restituisce -- che probabilmente non è niente (non l'ho mai usato quindi non posso esserne sicuro).
Il punto in cui chiami console.log
è all'interno della funzione di callback più interna. Al momento dell'esecuzione di questo pezzo di codice, il database ha risposto e la risposta è pronta per essere inviata al client. Ma si tenta di inviare i dati al client prima che venga eseguito questo callback.
Quindi l'approccio corretto consiste nell'inserire res.json
all'interno del callback più interno, che viene eseguito quando i dati sono disponibili.
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db('angular-auth');
dbo.collection('users').find({}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
res.json(result); // <-- res.json goes inside, after data is available
});
});
Sembra un problema di Async, ecco cosa puoi provare nel tuo file service.ts:
- Dovrai disporre di una sorta di modello mongo per contenere i dati. Per esempio:
private tasks:TaskModel[] = []
- Oltre a un modello, vorrai avere un soggetto che dovrai importare da rxjs.
import {Subject} from 'rxjs';
e
private taskUpdated = new Subject<taskModel>[](); //create a new subject of type taskModel that you will add to
- L'ultimo bit da aggiornare nel tuo file service.ts sarebbe questo:
getTasks(){
this.httpClient.get<any>(this.URL + '/tasks')
.subscribe((taskData)=> {
this.taskNotes = taskData;
this.taskUpdated.next([...this.taskNotes])//adding in taskNotes
})
getTasksUpdatedAsListener(){
return this.taskUpdated.asObservable();//observable that you will subscribe to in component.ts
}
- Quindi nel tuo file component.ts creerai un altro oggetto di sottoscrizione e cambierai il tuo codice in questo:
//subscription that needs to be created
private sub:Subscription;
ngOnInit(): void {
this.tasksService.getTasks()//this needs to go first. It will get data in the service file
this.sub = this.taskService.getTasksUpdatedAsListener()
.subscribe((data TaskModel[])=> {
console.log(data);//you should see the data come in as json
})
}
Fammi sapere come va!