ion date input with automatic submit upon selection - html

I'm new to ionic and I have this project that auto submits & shows reports when a date is selected. The problem is when I select a date the data isn't being submitted. Here is my .ts code.
async showRepo(item_date: Date) {
this.db.repoProduct(item_date).then((_) =>
{
console.log(_);
this.product = {};
});
}
And here is my .html code
<ion-item>
<ion-input
type="date"
(ionInput)='showRepo(item_date)'
></ion-input>
</ion-item>
Thanks in advance.

You can achieve this lot of ways. Create one variable and attach it with ion-input as a ngModel and use the ngModelChange event to catch the input change.
If you use the ion-datetime you can use the ionChange event to get the date change.
app.component.html
<ion-app>
<ion-header>
<ion-toolbar>
<ion-title>Hello</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-item>
<ion-label>Pick date</ion-label>
<ion-input
value="{{ date | date: 'dd.MM.yyyy' }}"
id="date"
class="ion-text-end"
></ion-input>
<ion-popover
size="cover"
trigger="date"
show-backdrop="false"
[dismissOnSelect]="true"
>
<ng-template>
<ion-datetime
#popoverDatetime
presentation="date"
[(ngModel)]="date"
locale="en-US"
(ngModelChange)="pickDateModelChange($event)"
(ionChange)="ionChangeEvent(popoverDatetime.value)"
></ion-datetime>
</ng-template>
</ion-popover>
</ion-item>
</ion-content>
</ion-app>
app.component.ts
import { Component, OnInit } from '#angular/core';
import { AlertController } from '#ionic/angular';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
private dateValue: any;
get date(): any {
return this.dateValue;
}
set date(value: any) {
console.log({ value });
this.dateValue = value;
}
constructor() {}
ngOnInit() {}
pickDateModelChange(dateValue): void {
console.log('ngModel change triggered');
console.log(dateValue);
//here you need to add your date format function and service call
}
ionChangeEvent(date: Date): void {
console.log('ion change event triggered');
console.log(date);
//here you need to add your date format function and service call
}
}
working example is here

Related

Ionic 4 read Local JSON file with Search Bar

Currently I've been facing issues with being able to do filtering on local JSON data in my Ionic project. I've looked at other resources and used that as reference when working on writing the filterItems function for the application. I haven't been receiving any errors in the console when using the function, however the table is not filtering or returning the filtered items to the ngx-datatable that I am using to display the data to the application. I am wondering if this problem has to do with either the filterItems function, or the way I am loading the data to the application from the local json file. Any assistance would be of great help. I'll be including both the HTML code and the typescript code.
HTML code
<ion-header>
<ion-toolbar color="primary">
<ion-buttons slot="start" class="button_style">
<ion-button (click)="switchStyle()">
{{ tablestyle }}
</ion-button>
</ion-buttons>
<ion-searchbar animated slot="end" (ionInput)="filterItems($event)" placeholder="Search by Path Request"></ion-searchbar>
</ion-toolbar>
</ion-header>
<ion-content>
<ngx-datatable class="request_table"
[ngClass]="tablestyle"
[rows]="items"
[columnMode]="'force'"
[headerHeight]="50"
[rowHeight]="'auto'">
<ngx-datatable-column name="requestid"></ngx-datatable-column>
<ngx-datatable-column name="number"></ngx-datatable-column>
<ngx-datatable-column name="requeststatus"></ngx-datatable-column>
<ngx-datatable-column name="animalcount"></ngx-datatable-column>
<ngx-datatable-column name="primaryinvestigator"></ngx-datatable-column>
<ngx-datatable-column name="studypathologist"></ngx-datatable-column>
<ngx-datatable-column name="Actions" sortable="false" prop="name">
<ng-template let-row="row" let-value="value" ngx-datatable-cell-template>
<ion-button size="small" fill="outline" (click)="goToProcedureDetails(row)">View</ion-button>
</ng-template>
</ngx-datatable-column>
</ngx-datatable>
</ion-content>
Typescript code
import { AlertController } from '#ionic/angular';
import { HttpClient } from '#angular/common/http';
import { Router, ActivatedRoute } from '#angular/router';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
#Component({
selector: 'app-request',
templateUrl: './request.page.html',
styleUrls: ['./request.page.scss'],
})
export class RequestPage implements OnInit {
items: any[];
searchItems: any;
public RequestFilter: string[];
tablestyle = 'bootstrap';
constructor(private alertCtrl: AlertController, private http: HttpClient, private router: Router) { }
ngOnInit() {
this.loadData();
}
loadData(){
let data:Observable<any>;
data = this.http.get('assets/requests.json');
data.subscribe(data => {
this.items = data;
console.log(this.items);
});
this.initializeItems();
}
initializeItems(){
this.RequestFilter = this.items;
}
goToProcedureDetails(row){
this.router.navigate(['/view-procedure', row.pathrequestid]);
console.log(row.pathrequestid);
}
filterItems(ev:any){
// Reset items back to all of the items
this.initializeItems();
// set val to the value of the searchbar
var val = ev.target.value;
// if the value is an empty string don't filter the items
if (val && val.trim() != '') {
this.RequestFilter = this.items.filter((item) => {
return (item.toString().toLowerCase().indexOf(val.toString().toLowerCase()) > -1);
})
}
}
}
You code can't work because you are filtering on object
items: any[];
return (item.toString().toLowerCase().indexOf(...
If you want to filter on one column (for example the requeststatus column), you can do that :
return (item.requeststatus.toString().toLowerCase().indexOf(val.toString().toLowerCase()) > -1);
If you want to filter on all columns of the table, I suggest you to take a look at this question

ionic 3 storage get data and show it in html

i want to show data in html from local storage but i got error [object promise]. i don't know how to show data in html. i can show data from console but cannot show in html. please help me
TS
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { Storage } from '#ionic/storage';
import { PengaturanPage } from "../../pengaturan/pengaturan";
#IonicPage()
#Component({
selector: 'page-biodata',
templateUrl: 'biodata.html',
})
export class BiodataPage {
inputnama: string;
public name: any;
constructor(public navCtrl: NavController,
public navParams: NavParams,
private storage: Storage) {`enter code here`
}
saveData(){
this.storage.set('name', this.inputnama);
}
loadData(){
this.storage.get('name').then((name) => {
console.log(name);
});
}
HTML :
<ion-row padding-top>
<ion-col class="col-tengah" col-10 no-padding>
<ion-item style="background: transparent" >
<ion-input class="input-biodata" [(ngModel)]="inputnama" placeholder="Nama">{{name}}</ion-input>
</ion-item>
</ion-col>
</ion-row>
You need to call saveData() and loadData() somewhere of course. I assume, you did this already.
To display the data in your template, you need to store the data in any attribute of your class. In your case you want to store it like this:
this.storage.get('name').then((name) => {
this.name = name;
});
After this Promise (Note: It is asynchronous, that is important to know), your name attribute is populated with any value your stored in LocalStorage before.
You maybe want to use .catch() on the Promise to catch any errors, that occur, when you have not stored any value for name.

Dynamic form using *ngFor and submitting values from it

I have a stackblitz as a guide.
I am wanting to display a list of material cards that I click an 'edit' button, to which I can edit text fields, and when I click on the 'save' icon, it of course saves by triggering an function etc.
I am struggling however to get to grips with how this all works within Angular and the Material nature of my app.
html
<form id="myForm" [formGroup]="thisIsMyForm">
<mat-card [formGroup]="x" *ngFor="let x of data; let i = index">
<mat-form-field>
<label for="{{x.name}}">Name</label>
<input formControlName="name" id="{{x.name}}" matInput value="{{x.name}}">
</mat-form-field>
<mat-form-field>
<label for="{{x.type}}">Type</label>
<input formControlName="type" id="{{x.type}}" matInput value="{{x.type}}"/>
</mat-form-field>
</mat-card>
</form>
ts
import { Component, ViewChild } from '#angular/core';
import {MatSnackBar} from '#angular/material';
import {FormArray, FormBuilder, FormGroup, Validators} from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
thisIsMyForm: FormGroup
data = [
{name:"one", type:"one"},
{name:"two", type:"two"},
{name:"three", type:"three"},
];
constructor(private formBuilder: FormBuilder) {}
onSubmit() {
// Here I would like to be able to access the values of the 'forms'
}
}
You are diving into the deep end for sure, trying to build a dynamic reactive form within the scope of an *ngFor is a challenge. I will walk you through it the best I can.
You will need to create an array for controls, in your constructor create your form setting formArrayName as an empty array using this.formBuild.array([])... call this whatever you want, I just used formArrayName for demonstration purposes.
After the form is instantiated with an empty array call this.buildForm()
constructor(private formBuilder: FormBuilder) {
this.thisIsMyForm = new FormGroup({
formArrayName: this.formBuilder.array([])
})
this.buildForm();
}
In your buildForm() iterate over your data[] and push controls for each index while assigning the default value and a default state of disabled.
buildForm() {
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
Object.keys(this.data).forEach((i) => {
controlArray.push(
this.formBuilder.group({
name: new FormControl({ value: this.data[i].name, disabled: true }),
type: new FormControl({ value: this.data[i].type, disabled: true })
})
)
})
console.log(controlArray)
}
Please Note: console.log(controlArray.controls) results in the following output... each index is a FormGroup with two controls name and type
0: FormGroup
1: FormGroup
2: FormGroup
In your html you will need to establish a container hierarchy that mimics the thisIsMyForm you just created.
parent:thisIsMyForm
child:formArrayName
grandchild:i as formGroupName
grandchild is important because it matches the console log of controlArray.controls in previous step
<form id="myForm" [formGroup]="thisIsMyForm">
<div [formArrayName]="'formArrayName'">
<mat-card *ngFor="let x of data; let i = index">
<div [formGroupName]="i">
Create edit and save buttons based on control disabled state
<button *ngIf="formControlState(i)" (click)="toggleEdit(i)">Enable Edit</button>
<button *ngIf="!formControlState(i)" (click)="toggleEdit(i)">Save</button>
Create methods in component to receive the index as an argument and handle logic to hide buttons and toggle input fields enable and disable state.
toggleEdit(i) {
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
if(controlArray.controls[i].status === 'DISABLED'){
controlArray.controls[i].enable()
}else{
controlArray.controls[i].disable()
}
}
formControlState(i){
const controlArray = this.thisIsMyForm.get('formArrayName') as FormArray;
return controlArray.controls[i].disabled
}
Submit button that console.log's the form value when clicked... also disable button while any of the input formControls are in enabled state.
<button [disabled]="thisIsMyForm.get('formArrayName').enabled" (click)="onSubmit()">Submit Form</button>
onSubmit() {
// Here I would like to be able to access the values of the 'forms'
console.log(this.thisIsMyForm.value)
}
Stackblitz
https://stackblitz.com/edit/dynamic-form-ngfor-otbuzn?embed=1&file=src/app/app.component.ts
Doing it with QueryList:
your html (this is an example):
<ng-container *ngFor="let x of data; let i = index">
<div class="ctr">
<span #names class="item">{{x.name}}</span>
<span #types class="item">{{x.type}}</span>
<span class="button" (click)="showData(i)">Show data</span>
</div>
</ng-container>
<h2>Selected values: </h2>
Selected name: {{selectedName}} <br>
Selected type: {{selectedType}}
some css just for the style
.ctr{
display: flex;
flex-direction: row;
margin-bottom: 20px;
}
.item{
margin-right:40px;
}
.button{
border: 1px solid black;
padding: 2px 5px 2px 5px;
cursor: pointer;
}
the component:
import { Component, QueryList, ViewChildren } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
#ViewChildren('names') names:QueryList<any>;
#ViewChildren('types') types:QueryList<any>;
selectedName: string;
selectedType: string;
data = [
{name:"one", type:1},
{name:"two", type:2},
{name:"three", type:3},
];
showData(index){
let namesArray = this.names.toArray();
let typesArray = this.types.toArray();
this.selectedName = namesArray[index].nativeElement.innerHTML;
this.selectedType = typesArray[index].nativeElement.innerHTML;
}
}
Working stackblitz: https://stackblitz.com/edit/angular-j2n398?file=src%2Fapp%2Fapp.component.ts

Show specific data for the clicked element using popover

when I retrieve data from a json file, in the *ngFor displays all the values in the popover, but I need a specific popover to display based only on the data for selected/clicked weapon. Here is my code any help would be greatly appreciated. Thank you again for your help
Home
import { Component } from '#angular/core';
import { NavController, ViewController, PopoverController, Events} from 'ionic-angular';
import { RestProvider } from './../../providers/rest/rest';
import { PopupPage } from './../../pages/popup/popup';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
weapons: any;
errorMessage: string;
constructor(public navCtrl: NavController, public rest: RestProvider,
public popoverCtrl: PopoverController) {
}
ionViewDidLoad() {
this.getweapons();
}
getweapons() {
this.rest.getweapons()
.subscribe(
weapons => this.weapons = weapons,
error => this.errorMessage = <any>error);
}
presentPopover(myEvent)
{
let popover = this.popoverCtrl.create(PopupPage);
popover.present({
ev: myEvent
});
}
}
home.html
<ion-content>
<ion-searchbar [(ngModel)]="terms"></ion-searchbar>
<ion-item>
</ion-item>
<ion-list>
<button ion-item (click)="presentPopover($event)">
<ion-item *ngFor="let c of weapons?.weapon_category?.weapons | search : terms">
<h2>{{c.name}}</h2>
</ion-item>
</button>
</ion-list>
</ion-content>
popup.ts
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, ViewController, Events} from 'ionic-angular';
import { RestProvider } from './../../providers/rest/rest';
import { HomePage } from './../../pages/home/home';
/**
* Generated class for the PopupPage page.
*
* See https://ionicframework.com/docs/components/#navigation for more info on
* Ionic pages and navigation.
*/
#IonicPage()
#Component({
selector: 'page-popup',
templateUrl: 'popup.html',
})
export class PopupPage {
rangeSettings = 20;
weapons: any;
errorMessage: string;
constructor(public navCtrl: NavController, public navParams: NavParams, public viewCtrl: ViewController, public rest: RestProvider) {
alert('inside the popup');
}
close() {
this.viewCtrl.dismiss();
}
getweapons() {
this.rest.getweapons()
.subscribe(
weapons => this.weapons = weapons,
error => this.errorMessage = <any>error);
}
ionViewDidLoad() {
this.getweapons();
}
}
popup.html
<ion-header>
<ion-navbar>
<ion-title>popup</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let c of weapons?.weapon_category?.weapons">
<h2>{{c.damage.base}}</h2>
<h2>{{c.damage.chest0}}</h2>
<h2>{{c.damage.chest1}}</h2>
<h2>{{c.damage.chest2}}</h2>
<h2>{{c.damage.chest3}}</h2>
<h2>{{c.damage.head1}}</h2>
<h2>{{c.damage.head2}}</h2>
<h2>{{c.damage.head3}}</h2>
</ion-item>
<ion-item>
<ion-range min="0" max="80" [(ngModel)]="rangeSettings" color="danger" pin="true" snaps="true" disabled=true></ion-range>
</ion-item>
</ion-list>
</ion-content>
Popover doesn't need to hit the REST call again. You can pass the chosen weapon to the popover as a parameter.
Change your function to accept a weapon (make sure you change the code in the HTML too)
presentPopover(myEvent, weapon)
And send it to the popover controller this way:
this.popoverCtrl.create(PopupPage, weapon);
Now in your popup.ts, decleare a weapon object in your class,
weapon : any;
and grab the weapon from the navParams in your constructor
this.weapon = this.navParams.data;
Change your <ion-item> in popup.html to display the selected one.
<ion-item>
{{weapon.damage.base}}
...
</ion-item>

Share data between components using Service - IONIC 2, Angular 2

Is there any way to send data {{error.value}} to another page using a method?
This is my code
<ion-row *ngFor="let errors of adp_principal_menuRS">
<ion-col class="info-col" col-4>
<button ion-button color="primary" small (click)="goToErrors(errors.event)">
{{errors.event}}
</button>
</ion-col>
</ion-row>
goToErrors(menu: string){
console.log(menu);
this.navCtrl.push(AdpDetailPage, {
});
}
I want to send the {{errors.event}} value to another page in the goToErrors() method.
Thanks!
EDIT: I just achieve what I want. I edited the code
Data can be shared using BehaviorSubject between components via service.
Here is an example:
// service.ts
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ShareService {
private errorSource = new BehaviorSubject<any>(null);
error$ = this.errorSource.asObservable();
setError(error: any){
this.errorSource.next(error);
}
Set the error event in parent component using setError method and subscribe the error in error component.
// error component.ts
constructor(share: ShareService) {
share.error$.subscribe(Err => this.error = Err);
Why don't you send the value using a navParam?
goToErrors(menu: string){
console.log(menu);
this.navCtrl.push(AdpDetailPage, {
errorEvent: menu // <------------------------- Add this line
});
}
And in your AdpDetailPage:
export class AdpDetailPage{
constructor(public navParams: NavParams){
errorEvent = this.navParams.get('errorEvent');
console.log("errorEvent= ", errorEvent);
}
}
Use event emittor.
//Home component.ts import { Events } from 'ionic-angular'; constructor(public events: Events) {} directioChange(user) {this.events.publish('directiochanged', 'true');} //App.component.ts constructor(public events: Events) { events.subscribe('directiochanged', (direction) => { this.isRtl = direction;console.log(direction);});}
I generated a Plunker that hopefully matches with what you are trying to do.
https://plnkr.co/edit/MNqpIqJjp5FN30bJd0RB?p=preview
Service
import { Injectable } from '#angular/core';
#Injectable()
export class ErrorService {
errorInfo: string;
}
Component
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<button (click)="goToErrors()">{{errors.event}} </button>
<router-outlet></router-outlet>
</div>
`,
})
export class App {
name:string;
errors = { event: 'Test Error', otherInfo: 'Test Info' };
constructor(private errorService: ErrorService, private router: Router) {
this.name = `Angular! v${VERSION.full}`
}
goToErrors(): void {
// Code to navigate to the other component
this.errorService.errorInfo = this.errors.event;
this.router.navigate(['/a']);
}
}