I'm storing a JSON Array via Ionic Storage like this:
this.storage.set('data', this.data).then().catch(err => {
this.data.splice(this.data.indexOf(Data), 1);
});
and fetching it in a function:
fetchData(){
this.storage.get('data').then(
(data: {value: string, usage: string, date: string, addedDate: string}[]) => {
this.data = data != null ? data : [];
console.log('DATA FETCHED: ' + data);
return data;
}
).catch(err => {
console.log(err);
});
}
I stored 4 objects in the array, but the console.log just gives me this back:
DATA FETCHED: [object Object],[object Object],[object Object],[object Object]
What should I do to get the array displayed right? I already tried with .toString() and .slice()
relevant part in home.html:
<ion-item *ngFor="let item of items">
<h2>{{ item.usage }}</h2>
<p>{{ item.date | date:'dd MMM yyyy' }}</p>
<h1 item-end ngClass="{{ item.value.charAt(0) === '-' ? 'expense' : 'income' }}">{{ item.value }} €</h1>
<!--<h1 item-end class="income">+ 450,00 €</h1>!-->
</ion-item>
home.ts:
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
items: any = this.moneyService.fetchData();
incomeval: any = IncomevalPage;
expenseval: any = ExpensevalPage;
constructor(public navCtrl: NavController, private moneyService: MoneyService) {}
ionViewWillEnter(){
this.items = this.moneyService.fetchData();
}
}
I think that, in addition to what Marco said in his answer, the problem is that you're not returning anything from fetchData(). The return statement is inside the promise. Promises might take a while to get used to, but if you return the result, it will be a new promise with the new value. It might be easier to understand with an example:
var promise = Promise.resolve("first").then(val => "second");
promise.then(val => console.log("val is", val));
// Prints: "val is second"
You are setting this.data of the MoneyService but it's not accessed anywhere in the HomePage component.
What if you change fetchData to this:
fetchData(){
return this.storage.get('data').then((data: {value: string, usage: string, date: string, addedDate: string}[]) => {
return data != null ? data : [];
});
}
It will now return a promise, which you will have to take care of properly in HomePage, maybe something like this (untested):
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
items: any;
incomeval: any = IncomevalPage;
expenseval: any = ExpensevalPage;
constructor(public navCtrl: NavController, private moneyService: MoneyService) {
moneyService.fetchData().then(result => this.items = result);
}
}
It will update this.items as soon as the data is available.
You need some corrections with home.ts:
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
items: any;
moneyService: any;
incomeval: any = IncomevalPage;
expenseval: any = ExpensevalPage;
constructor(public navCtrl: NavController, data: MoneyService) {
this.items = null;
this.moneyService = data;
}
ionViewWillEnter(){
this.items = this.moneyService.fetchData();
}
}
Related
I'm learning MEAN stack. I want to perform CRUD operations and I'm using mongoose. I am following this question on stackoverflow. I want to delete a document by specific value. In my case it is an article with a unique articleid which should get deleted. Unknowingly I'm doing some terrible mistake with params. Please correct me.
Sample document in mongodb.
{
_id: objectId("5d77de7ff5ae9e27bd787bd6"),
articleid:"art5678",
title:"Installing JDK 8 in Ubuntu 18.04 and later",
content:"<h2>Step 1: Add repository</h2><p><strong>$ sudo add-apt-repository pp..."
date:"Tue, 10 Sep 2019 17:33:51 GMT"
contributor:"Tanzeel Mirza",
__v:0
}
article.component.html
<div class="row mt-5">
<div class="col-md-4 mb-3" *ngFor="let article of articles;">
<div class="card text-center">
<div class="card-body">
<h5 class="card-title">{{article.title}}</h5>
<a (click)="onPress(article.articleid)" class="btn btn-danger">Delete</a>
</div>
</div>
</div>
</div>
(click)="onPress(article.articleid") calls a method in ts file.
article.component.ts
import { Component, OnInit } from '#angular/core';
import { ArticleService } from '../article.service';
#Component({
selector: 'app-articles',
templateUrl: './articles.component.html',
styleUrls: ['./articles.component.css']
})
export class ArticlesComponent implements OnInit {
articles = []
constructor(private _articleService: ArticleService) { }
ngOnInit() {
this._articleService.getEvents()
.subscribe(
res => this.articles = res,
err => console.log(err)
)
}
onPress(id) {
this._articleService.deleteArticle()
.subscribe (
data => {
console.log("hello");
}
);
}
}
I have created a service article.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ArticleService {
private _deleteUrl = "http://localhost:3000/api/delete/:id";
constructor(private http: HttpClient) { }
getAllArticles() {
...
}
deleteArticle(id) {
return this.http.delete<any>(this._deleteUrl);
}
}
And here is my api.js
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Article = require('../models/article');
const dbstring = ...
mongoose.connect(dbstring, { useNewUrlParser: true }, err => {
...
})
router.delete('/delete/:id', (req, res) => {
let articleData=req.params.id;
console.log(articleData); //Output: {}
console.log('on delete url '+articleData); //Output: on delete url undefined
Article.deleteOne({articleid: articleData}, (error, article) => {
if(error) {
console.log(error)
}
else {
if(!article) {
res.status(401).send('Something went wrong')
}
else {
//res.json(article);
}
}
})
})
module.exports = router;
Ok dont write the code for me, but please at least tell me some study material.
Ok. I did more and more research and figured out the problem. Here are the changes.
api.js
router.delete('/delete/:id', (req, res) => {
let articleId=req.params.id;
Article.deleteOne({articleid: articleId}, (error, article) => {
if(error) {
console.log(error)
}
else {
if(!article) {
...
}
else {
...
}
}
})
})
and article.service.ts
private _deleteUrl = "http://localhost:3000/api/delete";
deleteArticle method should be.
deleteArticle(id) {
return this.http.delete<any>(this._deleteUrl+'/'+id);
}
hello I'm learning angular 6 but I don't understand why it doesn't display my message but he appears in the logs of my server.
component:
import { Component } from '#angular/core';
import { ChatService } from '../chat.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
message: string;
messages: string[] = [];
constructor(private chatService: ChatService) {
}
sendMessage() {
this.chatService.sendMessage(this.message);
this.message = '';
}
OnInit() {
this.chatService
.getMessages()
.subscribe((message: string) => {
this.messages.push(message);
});
}
}
html:
<div>
<li *ngFor="let message of messages">
{{message}}
</li>
</div>
<input [(ngModel)]="message" (keyup)="$event.keyCode == 13 && sendMessage()" />
<button (click)="sendMessage()">Send</button>
thanks for your help
chat service :
import * a io from 'socket.io-client';
import {Observable} from 'rxjs';
export class ChatService{
private url = 'http://localhost:3000';
private socket;
constructor() {
this.socket = io(this.url);
}
public sendMessage(message){
this.socket.emit('new-message',message);
}
public getMessage = () => {
return Observable.create((observer) => {
this.socket.on('new-message' , (message) => {
observer.next(message);
});
});
}
}
I want to retrieve places coordinates from restApi and display them on the map.
I got error : Cannot read property 'length' of undefined
Please help me !
I want you to tell me how i can get my data in order to add multiple markers.
This is my portion of code
import { Component, ViewChild, ElementRef } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
import { Geolocation } from '#ionic-native/geolocation';
import { RestProvider } from '../../providers/rest/rest';
declare var google;
#Component({
selector: 'page-localisation',
templateUrl: 'localisation.html',
})
export class LocalisationPage {
#ViewChild('map') mapElement: ElementRef;
map: any;
places: Array<any>;
errorMessage : string;
constructor(public navCtrl: NavController, public navParams: NavParams, public geolocation: Geolocation, public rest: RestProvider) {
}
ionViewDidLoad(){
this.loadMap();
this.getPlaces();
this.addPlacesToMap()
console.log("Length : " + this.places.length) ; //Error Cannot read property 'length' of undefined
}
getPlaces() {
this.rest.getPlaces().subscribe(
places => this.places = places,
error => this.errorMessage = <any>error
);
}
loadMap(){
let latLng = new google.maps.LatLng(-4.066548, 5.356315);
let mapOptions = {
center: latLng,
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
this.map = new google.maps.Map(this.mapElement.nativeElement, mapOptions);
}
addPlacesToMap(){
//...
}
addInfoWindow(marker, content){
let infoWindow = new google.maps.InfoWindow({
});
content: content
google.maps.event.addListener(marker, 'click', () => {
infoWindow.open(this.map, marker);
});
}
}
ionViewDidLoad is launched before "this.rest.getPlaces().subscribe" is finished... So your variable "places" is NULL
Change getPlaces to a Promise
async getPlaces() {
places = await this.rest.getPlaces() ;
return places
}
Then in ionViewDidLoad
ionViewDidLoad(){
var that = this ;
this.loadMap();
this.getPlaces().then((places)=>{
that.places = places;
console.log("Length : " + that.places.length) ;
});
this.addPlacesToMap()
}
Good day,
How can i handle input type file in formControl? im using reactive form but when i get the value of my form it returns null value on my <input type="file">??
You need to write your own FileInputValueAccessor. Here is the plunker and the code:
#Directive({
selector: 'input[type=file]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: FileValueAccessorDirective,
multi: true
}
]
})
export class FileValueAccessorDirective implements ControlValueAccessor {
onChange;
#HostListener('change', ['$event.target.value']) _handleInput(event) {
this.onChange(event);
}
constructor(private element: ElementRef, private render: Renderer2) { }
writeValue(value: any) {
const normalizedValue = value == null ? '' : value;
this.render.setProperty(this.element.nativeElement, 'value', normalizedValue);
}
registerOnChange(fn) { this.onChange = fn; }
registerOnTouched(fn: any) { }
nOnDestroy() { }
}
And then you will be able to get updates like this:
#Component({
moduleId: module.id,
selector: 'my-app',
template: `
<h1>Hello {{name}}</h1>
<h3>File path is: {{path}}</h3>
<input type="file" [formControl]="ctrl">
`
})
export class AppComponent {
name = 'Angular';
path = '';
ctrl = new FormControl('');
ngOnInit() {
this.ctrl.valueChanges.subscribe((v) => {
this.path = v;
});
}
}
there is no way to handle this in angular form-control.
we can provide some hack to make this work if you want to upload the image.
just add the <input type=file> as form control on which user can add the file and acter grabbing the file we can change it to the base64code and then assign that value to the hidden field of our main form.
then we can store the image file in that way.
else you can go for the ng-file-upload moduleng file upload
How i access super component class variable into sub component in Angular2?
super Component Article.ts
#Component({
selector: 'article'
})
#View({
templateUrl: './components/article/article.html?v=<%= VERSION %>',
styleUrls : ['./components/article/article.css'],
directives: [CORE_DIRECTIVES, AmCard, NgFor]
})
export class Article{
articleArr : Array;
constructor() {
this.articleArr = new Array();
}
articleSubmit(articleSubject, articleName, articleUrl)
{
this.articleArr.push({title: articleSubject.value, user : articleName.value, url : articleUrl.value});
}
}
super Component article.html
<div *ng-for="#item of articleArr">
<am-card card-title="{{item.title}}" card-link="{{item.url}}" card-author="{{item.user}}"></am-card>
</div>
sub component amcard.ts
#Component({
selector: 'am-card',
properties : ['cardTitle', 'cardLink', 'cardAuthor']
})
#View({
templateUrl: './components/card/card.html?v=<%= VERSION %>',
styleUrls : ['./components/card/card.css'],
directives: [CORE_DIRECTIVES]
})
export class AmCard {
constructor() {
}
}
sub Component amcard.html
<div class="card">
...
</div>
So my question is how to access articleArr of Article Class in AmCard class ?
advanced
Thanks for helping me.
You can inject a parent component into a child using angular2 Dependency Injection. Use #Inject parameter decorator and forwardRef to do it (forwardRef allows us to refer to Article which wasn't yet defined). So your AmCard component will look like (see this plunker):
#Component({
selector: 'am-card',
template: `
<span>{{ articleLength }} - {{ cardTitle }}<span>
`
})
export class AmCard {
#Input() cardTitle: string;
#Input() cardLink: string;
#Input() cardAuthor: string;
constructor(#Inject(forwardRef(() => Article)) article: Article) {
// here you have the parent element - `article`
// you can do whatever you want with it
this.articleLength = article.articleArr.length;
setTimeout(() => {
article.articleSubmit({ value: Math.random() }, {}, {});
}, 1000)
}
}
But, IMHO, it's a bad pattern. If possible, it's much better to use output property (event binding) to pass message to a parent component and in a parent component handle that message. In your case it would look like (see this plunker):
#Component({ /* ... component config */})
class AmCard {
// ... input properties
#Output() callSubmit = new EventEmitter();
constructor() {
setTimeout(() => {
// send message to a parent component (Article)
this.callSubmit.next({ value: Math.random() });
}, 1000)
}
}
#Component({
// ... component config
template: `
<h3>Article array:</h3>
<div *ng-for="#item of articleArr">
<am-card
[card-title]="item.title"
[card-link]="item.url"
[card-author]="item.user"
`/* handle message from AmCard component */+`
(call-submit)=" articleSubmit($event, {}, {}) "
></am-card>
</div>
`
})
class Article{
// ... properties and constructor
articleSubmit(aa, an, au) {
this.articleArr.push({ title: as.value, user: an.value, url: au.value });
}
}