I am trying to send data to my popover component but it doesn't send the data.
Code
HTML
<div class="message" id="conversation" *ngFor="let message of messages.notes">
<ion-row class="message-body">
<ion-col (click)="presentPopover($event)" size="12" class="message-main-sender" *ngIf="message.user.id === user.id; else receiverNote">
// rest of message detail...
</ion-col>
</ion-row>
</div>
component
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
component: MessagesComponent,
cssClass: 'my-custom-class',
event: ev,
translucent: true
});
return await popover.present();
}
popover component (can't get sent data in here )
reply() {
console.log('my_data1 : ', this.navParams.get('data')); // undefined
console.log('my_data2 : ', this.activatedRoute.snapshot.paramMap.get('event')); // null
}
Any idea?
You can use componentProps to send data to your popover
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
component: MessagesComponent,
cssClass: 'my-custom-class',
event: ev,
translucent: true,
componentProps: {
id: 1
}
});
return await popover.present();
}
Get the data in the MessagesComponent with navParams:
constructor(private navParams: NavParams) {}
ngOnInit() {
console.log(this.navParams.get('id')); // 1
}
Send data back to original page
Send data back in your component with dismiss.
this.popoverController.dismiss({ id: 1 });
Ready to receive it inside the constructed presentPopover function
async presentPopover(ev: any) {
const popover = await this.popoverController.create({
// ...
});
popover.onDidDismiss().then((result: object) => {
if (result['data']) {
console.log(result['data'].id) // 1
}
});
return await popover.present();
}
Related
I have a page that I use to show 3 differents html depending on where it is called.
In a page I have:
openCreateAnagraphics(){
this.router.navigate(["/anagraphics", {customerUpdate: true}]);
}
So I'm navigate to anagraphics.
there I have in my anagraphics.page.ts:
ngOnInit() {
this.handleParams();
}
handleParams() {
let params = this.route.snapshot.params;
console.log("this.route.snapshot", this.route.snapshot)
console.log("params", params)
this.customerUpdate = params.customerUpdate ? params.customerUpdate : false
console.log("this.customerUpdate ", this.customerUpdate)
}
and in the anagraphics.page.html
<div *ngIf="....">
<div>
//this is showed if I come from another way
</div>
</div>
<div *ngIf="customerUpdate">
<div>
HELLO // there is the problem
</div>
</div>
but I see only a white page and my url is
http://localhost:4200/anagraphics;customerUpdate=true
I would to obtain that I if i click on the button that calls openCreateAnagraphics, I'll go in a page that show the html when customerUpdate = true.
EDIT 1:
In my app-routing.module.ts
{ path: 'anagraphics', loadChildren: () => import('./anagraphics/anagraphics.module').then(m => m.AnagraphicPageModule), canActivate: [AuthGuard], data: { configurator: true, customerUpdate: false } },
but in this way customerUpdate is always on false.
My solution reference link: https://angular.io/api/router/RouterEvent
In your .routing.module.ts file add data like the below.
const routes: Routes = [{
path: '',
component: AlertsComponent,
data: {
// What data you want to pass add that here
}
}]
Then get that value in your common component like below. (Like: app or nav component)
constructor(public router: Router) {
router.events.pipe(
filter((e: Event): e is RouterEvent => e instanceof RouterEvent)
).subscribe((e: RouterEvent) => {
// Get your route data here
});
}
I am using a 'Custom Datatable' solution in order to modify picklist values within a datatable. Project code may be referenced here:
https://live.playg.app/play/picklist-in-lightning-datatable
I have made changes so that I can retrieve data from the custom object: Payment__c, and I am attempting modify the picklist values for the Payment_Status__c field. My 'debugging' method has been to create numerous console.log statements to verify data during the updating process. Picklist values are currently hardcoded (have not figured out how to dynamically pull from SF yet). Inline edit of individual cells works fine, and I am able to save those values as well (though changes are not reflected until I perform a manual page refresh). Picklist selection is working, but I am unable to save the currently selected picklist value in the datatable.
I believe that the intended trigger event for picklist selection changes--'valueselect', is not being fired, and the handleSelection method is not receiving this event when a new picklist selection is made.
The lightning component used on Salesforce is c-customDatatableDemo:
customDatatableDemo.js
import { LightningElement, track, wire } from 'lwc';
import getPayments from '#salesforce/apex/PaymentController.getPayments';
import saveRecords from '#salesforce/apex/PaymentController.saveRecords';
import { updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '#salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class CustomDatatableDemo extends LightningElement {
#track data = [];
//have this attribute to track data changed
//with custom picklist or custom lookup
#track draftValues = [];
#track lastSavedData = [];
connectedCallback() {
this.columns = [
{
label: 'Name',
fieldName: 'Name',
editable: false
}, {
label: 'Invoice Number',
fieldName: 'Invoice_Number__c',
editable: true
}, {
label: 'Invoice Amount',
fieldName: 'Invoice_Amount__c',
type: 'currency',
editable: true
}, {
label: 'Invoice Date',
fieldName: 'Invoice_Date__c',
type: 'date',
editable: true
}, {
label: 'Payment Status',
fieldName: 'Payment_Status__c',
type: 'picklist',
typeAttributes:
{
placeholder: 'Choose Status',
options: [
{ label: 'Needs to Be Paid', value: 'Needs to Be Paid' },
{ label: 'Issued', value: 'Issued' },
{ label: 'Voided', value: 'Voided' },
] // List of Payment Status picklist options
, value: {fieldName: 'Payment_Status__c' } // default value for picklist
, context: {fieldName: 'Id' } // binding Payment Id with context variable to be returned back
}
},
{
label: 'Description', fieldName: 'Work_Description__c', type: 'text', editable: true
}];
// Get Payments data
getPayments()
.then(result => {
this.data = result;
this.error = undefined;
})
.catch(error => {
this.error = error;
this.data = undefined;
})
// Save last saved copy
this.lastSavedData = JSON.parse(JSON.stringify(this.data));
}
updateDataValues(updateItem) {
console.log('START--updateDataValues()');
let copyData = [... this.data];
copyData.forEach(item => {
if (item.Id === updateItem.Id) {
for (let field in updateItem) {
console.log('updateDataValues() item.Id = ' + JSON.stringify(updateItem.Id));
console.log('updateItem[field] = ' + JSON.stringify(updateItem[field]));
item[field] = updateItem[field];
console.log('UPDATED--item[field] = ' + updateItem[field]);
}
}
});
//write changes back to original data
this.data = [...copyData];
console.log('this.data = ' + JSON.stringify(this.data));
let tempData = [...this.data];
//console.log('tempData = ' + JSON.stringify(tempData));
console.log('END--updateDataValues()');
}
updateDraftValues(updateItem) {
console.log('START--updateDraftValues()');
console.log('stringify draft updateItem = ' + JSON.stringify(updateItem));
let draftValueChanged = false;
let copyDraftValues = [...this.draftValues];
//store changed value to do operations
//on save. This will enable inline editing &
//show standard cancel & save button
let i = 0;
copyDraftValues.forEach(item => {
if (item.Id === updateItem.Id) {
i++;
console.log('i = ' + i);
for (let field in updateItem) {
console.log(i + '. UpdateDraftValues--item id if selected...item Id = ' + item.Id + ' & item value = ' + item.value);
item[field] = updateItem[field];
console.log('item[field] = ' + updateItem[field]);
}
draftValueChanged = true;
console.log('draftValueChanged = TRUE');
}
});
//draftValueChanged = true;
if (draftValueChanged) {
console.log('YESdraftValueChanged');
console.log('copyDraftValues = ' + JSON.stringify(copyDraftValues));
this.draftValues = [...copyDraftValues];
//console.log('draftValues = ' + JSON.stringify(draftValues));
} else {
console.log('NOdraftValue!Changed');
this.draftValues = [...copyDraftValues, updateItem];
let testDraftValues = {... this.draftValues};
console.log('JSON.stringify(testDraftValues) = ' + JSON.stringify(testDraftValues));
}
console.log('STOP--updateDraftValues()')
}
//listener handler to get the context and data
//updates datatable
picklistChanged(event) {
console.log('START--picklistChanged()');
console.log('EVENT type - ' + event.type);
event.stopPropagation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
console.log('picklistChanged()...updatedItem = ' + JSON.stringify(updatedItem));
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
/* console.log('event.value = ' + event.value);
this.value = event.target.value;
event.stopPropagation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
console.log('updatedItem.context ' + updatedItem.context);
console.log('updatedItem.value ' + updatedItem.value);
console.log('updatedItem = ' + JSON.stringify(updatedItem));
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
console.log('picklistChanged() = ' + JSON.stringify(updatedItem)); */
console.log('STOP--picklistChanged()');
}
handleSelection(event) {
console.log('START--handleSelection()');
this.updateDraftValues(event.detail.draftValues[0]);
console.log('this.updateDraftValues(event.detail.draftValues[0]);')
/* event.stopPropogation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
this.updateDraftValues(updatedItem);
this.updateDraftValues(updatedItem); */
console.log('STOP--handleSelection() = ' + JSON.stringify(updatedItem));
}
//handler to handle cell changes & update values in draft values
handleCellChange(event) {
console.log('START--handleCellChange()');
console.log('handleCellChange');
this.updateDraftValues(event.detail.draftValues[0]);
console.log('handleCellChange value = ' + JSON.stringify(this.updateDraftValues));
console.log('END--handleCellChange()');
}
handleSave(event) {
if (event.type === 'picklistchanged'){
}
console.log('START--handleSave');
console.log('Updated items = ', this.draftValues);
// save last saved copy
this.lastSavedData = JSON.parse(JSON.stringify(this.data));
console.log('this.lastSavedData = ' + JSON.stringify(this.lastSavedData));
this.fldsItemValues = event.detail.draftValues;
console.log('this.fldsItemValues = ' + JSON.stringify(this.fldsItemValues));
const inputsItems = this.fldsItemValues.slice().map(draft => {
const fields = Object.assign({}, draft);
console.log('JSON.stringify() fields ' + JSON.stringify(fields));
return { fields };
});
// Show toast after successful update
const promises = inputsItems.map(recordInput => updateRecord(recordInput));
Promise.all(promises).then(res => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Records Updated Successfully!!',
variant: 'success'
})
);
this.fldsItemValues = [];
return this.refresh();
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error',
message: 'An Error Occured!!',
variant: 'error'
})
);
}).finally(() => {
// Clear draft values
this.draftValues = [];
});
// Refresh the window after successful save
//window.open('url','_self');
//document.location.reload(true);
//cmp.find("table-component-id").set("v.draftValues", null);
console.log('END--handleSave');
}
handleCancel(event) {
//remove draftValues & revert data changes
this.data = JSON.parse(JSON.stringify(this.lastSavedData));
this.draftValues = [];
}
async refresh() {
console.log('async refresh');
await refreshApex(this.data);
//this.connectedCallback();
}
}
customDatatableDemo.html
<template>
<lightning-card title="Invoicing" icon-name="custom:custom17">
<div class="slds-var-m-around_medium">
<template if:true={data}>
<c-custom-data-table
object-api-name="Payment__c"
key-field="Id"
data={data}
value=""
show-row-number-column
columns={columns}
onpicklistchanged={picklistChanged}
onvalueselect={handleSelection}
draft-values={draftValues}
oncellchange={handleCellChange}
onsave={handleSave}
oncancel={handleCancel}>
</c-custom-data-table>
<template if:true={data.error}></template>
</template>
</div>
</lightning-card>
<p>Selected value is: {value}</p>
</template>
customDataTable.js
import LightningDatatable from 'lightning/datatable';
//import the template so that it can be reused
import DatatablePicklistTemplate from './picklist-template.html';
import { loadStyle } from 'lightning/platformResourceLoader';
import CustomDataTableResource from '#salesforce/resourceUrl/CustomDataTable';
export default class CustomDataTable extends LightningDatatable {
static customTypes = {
picklist: {
template: DatatablePicklistTemplate,
typeAttributes: ['label', 'placeholder', 'options', 'value', 'context'],
},
};
constructor() {
super();
Promise.all([
loadStyle(this, CustomDataTableResource),
]).then(() => {})
}
}
picklist-template.html (Same folder as customDataTable)
<template>
<c-datatable-picklist label={typeAttributes.label} value={typeAttributes.value}
placeholder={typeAttributes.placeholder} options={typeAttributes.options} context={typeAttributes.context}>
</c-datatable-picklist>
</template>
datatablePicklist.js
import { LightningElement, api, track } from 'lwc';
export default class DatatablePicklist extends LightningElement {
#api label;
#api placeholder;
#api options;
#api value;
#api context;
handleChange(event) {
//show the selected value on UI
this.value = event.detail.value;
//fire event to send context and selected value to the data table
this.dispatchEvent(new CustomEvent('picklistchanged', {
composed: true,
bubbles: true,
cancelable: true,
detail: {
data: { context: this.context, value: this.value }
}
}));
}
}
datatablePicklist.html
<template>
<div class="picklist-container">
<lightning-combobox name="picklist" label={label} value={value} placeholder={placeholder} options={options}
onchange={handleChange}></lightning-combobox>}
</div>
</template>
lwcEditSaveRow.js
import { LightningElement, wire, track } from 'lwc';
import getAccounts from '#salesforce/apex/lwcEditSaveRowCtrl.getAccounts';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '#salesforce/apex';
const columns = [
{
label: 'Name',
fieldName: 'Name',
type: 'text',
}, {
label: 'Phone',
fieldName: 'Phone',
type: 'phone',
editable: true,
}, {
label: 'Industry',
fieldName: 'Industry',
type: 'text',
editable: true,
}, {
label: 'Type',
fieldName: 'Type',
type: 'text',
editable: true
}, {
label: 'Description',
fieldName: 'Type',
type: 'text',
editable: true
}
];
export default class LwcEditSaveRow extends LightningElement {
columns = columns;
#track accObj;
fldsItemValues = [];
#wire(getAccounts)
cons(result) {
this.accObj = result;
if (result.error) {
this.accObj = undefined;
}
};
saveHandleAction(event) {
this.fldsItemValues = event.detail.draftValues;
const inputsItems = this.fldsItemValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
const promises = inputsItems.map(recordInput => updateRecord(recordInput));
Promise.all(promises).then(res => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Records Updated Successfully!!',
variant: 'success'
})
);
this.fldsItemValues = [];
return this.refresh();
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error',
message: 'An Error Occured!!',
variant: 'error'
})
);
}).finally(() => {
this.fldsItemValues = [];
});
}
async refresh() {
await refreshApex(this.accObj);
}
}
lwcEditSaveRow.html
<template>
<lightning-card>
<div class="slds-m-around_medium">
<h3 class="slds-text-heading_medium"><lightning-icon icon-name="custom:custom84" size="small"></lightning-icon> <strong style="color:#270086; font-size:13px; margin-right:5px;"> How to inline Edit/Save Rows With Lightning Datatable in Lightning Web Component (LWC) </strong></h3>
<br/><br/>
<template if:true={accObj.data}>
<lightning-datatable key-field="Id"
data={accObj.data}
columns={columns}
onsave={saveHandleAction}
draft-values={fldsItemValues}
hide-checkbox-column
show-row-number-column>
</lightning-datatable>
</template>
<br/>
<br/>
<!--Start RelatedTopics Section-->
<div style="border:1px #ddd solid; padding:10px; background:#eee; margin:40px 0;">
<p data-aura-rendered-by="435:0"><img src="https://www.w3web.net/wp-content/uploads/2021/05/thumbsUpLike.png" width="25" height="25" style="vertical-align:top; margin-right:10px;" data-aura-rendered-by="436:0"><strong data-aura-rendered-by="437:0"><span style="font-size:16px; font-style:italic; display:inline-block; margin-right:5px;">Don't forget to check out:-</span>An easy way to learn step-by-step online free Salesforce tutorial, To know more Click <span style="color:#ff8000; font-size:18px;" data-aura-rendered-by="442:0">Here..</span></strong></p>
<br/><br/>
<p data-aura-rendered-by="435:0"><img src="https://www.w3web.net/wp-content/uploads/2021/07/tickMarkIcon.png" width="25" height="25" style="vertical-align:top; margin-right:10px;" data-aura-rendered-by="436:0"><strong data-aura-rendered-by="437:0"><span style="font-size:17px; font-style:italic; display:inline-block; margin-right:5px; color:rgb(255 128 0);">You May Also Like →</span> </strong></p>
<div style="display:block; overflow:hidden;">
<div style="width: 50%; float:left; display:inline-block">
<ul style="list-style-type: square; font-size: 16px; margin: 0 0 0 54px; padding: 0;">
<li>How to get selected checkbox value in lwc</li>
<li>how to display account related contacts based on AccountId in lwc</li>
<li>how to create lightning datatable row actions in lwc</li>
<li>how to use if and else condition in lwc</li>
<li>how to display selected radio button value in lwc</li>
</ul>
</div>
<div style="width: 50%; float:left; display:inline-block">
<ul style="list-style-type: square; font-size: 16px; margin: 0 0 0 54px; padding: 0;">
<li>display account related contacts based on account name in lwc</li>
<li>how to insert a record of account Using apex class in LWC</li>
<li>how to get picklist values dynamically in lwc</li>
<li>how to edit/save row dynamically in lightning component</li>
<li>update parent field from child using apex trigger</li>
</ul>
</div>
<div style="clear:both;"></div>
<br/>
<div class="youtubeIcon">
<img src="https://www.w3web.net/wp-content/uploads/2021/11/youtubeIcon.png" width="25" height="25" style="vertical-align:top; margin-right:10px;"/> <strong>TechW3web:-</strong> To know more, Use this <span style="color: #ff8000; font-weight: bold;">Link</span>
</div>
</div>
</div>
<!--End RelatedTopics Section-->
</div>
</lightning-card>
</template>
Example of changing and saving non-picklist value in datatable:
Changing and saving non-picklist value
Example of changing and saving a picklist value:
Changing and saving picklist value (1)
Last bit of console output:
Changing and saving picklsit value (2)
As this is my first time working with Lightning Web components, I would greatly appreciate any assistance you may provide. Thanks in advance.
I was able to get this custom data table component working for something I am developing to effectively bind records as rows. Here 2 differences I notice:
I did not include onvalueselect and oncellchange methods for the component html declaration, only the onpicklistchanged.
You may want to use your custom server side controller method instead of the built-in uiRecordApi->updateRecord one. Something tells me this may not play nice with row data from the data table. In my implementation, I was simply able to pass the draftValues over to the server side method which has a single parameter of list of sObject:
async saveRecords(event){
const updatedFields = event.detail.draftValues;
this.draftValues = [];
this.showSpinner = true
try{
await saveRelatedRecords({sObjs: updatedFields}) // server side save
.then((result) => {
this.updateMessage = result;
})
this.showSpinner = false;
if(this.updateMessage == 'success'){
this.showToast('Success', 'Record(s) Updated', 'success');
} else{
this.showToast('Error', this.updateMessage, 'error');
}
await refreshApex(this._wiredRecordData);
this.unsavedData = this.records;
} catch (error) {
this.showSpinner = false;
this.showToast('Error while updating or refreshing records', error.body.message, 'error');
}
}
In regards to your data not refreshing, I suggest you wire your getPayments method so that you can always get a fresh set from the server side, rather than trying to keep track of and maintain data changes on the client side, something like:
_wiredRecordData;
#wire(getRelatedRecords)
relatedRecords(getRecsResult){
const { data, error } = getRecsResult;
this._wiredRecordData = getRecsResult;
if(data){
this.records = data;
}
}
Then after your success toast in your save method, you can use
await refreshApex(_wiredRecords); and lwc knows to rerender based on the wiring (or at least I think that's how it works.)
Lastly, here is the server side controller method I have to dynamically generate column header information so it does not need to be hard coded into the component. However I did need to modify the custom component a bit to include a new "fieldapi" attribute so that the client side method knows what field to set for the changed value during the onpicklistchanged action.
#AuraEnabled(cacheable=true)
public static String getColumnHeaders(String sObjAPI, String fieldAPIs)
{
List<ColumnHeaderInfo> colHeaders = new List<ColumnHeaderInfo>();
Schema.DescribeSObjectResult sObjDesc = Schema.getGlobalDescribe().get(sObjAPI).getDescribe();
Boolean objIsUpdateable = sObjDesc.isUpdateable();
Map<String, Schema.SObjectField> objFields = sObjDesc.fields.getMap();
for(String field: fieldAPIs.split(','))
{
if(!objFields.keySet().contains(field.toLowerCase())){
continue;
}
Schema.DescribeFieldResult fieldDesc = objFields.get(field).getDescribe();
if(!fieldDesc.isAccessible()){
continue;
}
ColumnHeaderInfo colHeader = new ColumnHeaderInfo();
colHeader.label = fieldDesc.getLabel();
colHeader.fieldName = fieldDesc.getName();
colHeader.editable = fieldDesc.isUpdateable() && sObjDesc.isUpdateable();
colHeader.type_x = fieldDesc.getType().name().toLowerCase();
if(colHeader.type_x == 'picklist')
{
colHeader.type_x = 'picklist';
List<Schema.PicklistEntry> picklistValues = fieldDesc.getPicklistValues();
colHeader.typeAttributes = new TypeAttributes();
colHeader.typeAttributes.options = new List<Option>();
for(Schema.PicklistEntry ple: picklistValues)
{
Option opt = new Option();
opt.value = ple.getValue();
opt.label = ple.getLabel();
colHeader.typeAttributes.options.add(opt);
}
colHeader.typeAttributes.context = new FieldName();
colHeader.typeAttributes.context.fieldName = 'Id';
colHeader.typeAttributes.value = new FieldName();
colHeader.typeAttributes.value.fieldName = fieldDesc.getName();
colHeader.typeAttributes.fieldapi = fieldDesc.getName();
}
// multi-select picklist fields not supported so make them read-only
if(colHeader.type_x == 'multipicklist'){
colHeader.editable = false;
}
colHeaders.add(colHeader);
}
return JSON.serialize(colHeaders).replaceAll('type_x', 'type');
}
private class ColumnHeaderInfo
{
public String label;
public String fieldName;
public String type_x;
public Boolean editable;
public TypeAttributes typeAttributes;
}
private class TypeAttributes
{
public String placeholder;
public List<Option> options;
public FieldName value;
public FieldName context;
public FieldName label;
public FieldName tooltip;
public String fieldapi;
public String target;
}
private class Option
{
public String label;
public String value;
}
private class FieldName
{
public String fieldName;
}
Currently, when a button is clicked, an axios call will retrieve some information about a particular product and open, AT THE SAME TIME, a v-dialog showing all the information about the product.
The behavior I would like would rather be that the v-dialog opens ONLY AFTER the axios call is completed. I know that async functions would be usefull here, but the fact that the same button call the axios function AND opens the v-dialog is what's confusing me here.
Here's my code in template:
<v-dialog v-model="productInfoDialog" max-width="600px" :retain-focus="false">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" v-bind="attrs" v-on="on" v-on:click="getProductInfo(row.item.id)">View Product</v-btn>
</template>
...dialog content
</v-dialog>
In script:
closeDialog() {
this.productInfoDialog = false;
},
getProductInfo(id) {
var url = this.$store.getters.URLs.Product.url;
axios.get(url, {
params: this.getProductParams(id),
})
.then((response) => {
//product info assignment
})
.catch((error) => {
console.log(error.response);
})
},
Thanks in advance for your help! :)
If got what you want just do it.
closeDialog() {
this.productInfoDialog = false;
},
getProductInfo(id) {
var url = this.$store.getters.URLs.Product.url;
axios.get(url, {
params: this.getProductParams(id),
})
.then((response) => {
//here the request is completed
//so you can open your dialog now
this.productInfoDialog = true;
this.productInfo.id = id;
this.productInfo.img_url = response.data.data[0].img_url;
this.productInfo.ecommerceUrl = response.data.data[0].url_en;
})
.catch((error) => {
this.productInfo.id= '';
this.productInfo.img_url = '';
this.productInfo.ecommerceUrl = '';
console.log(error.response);
})
}
I create a mobile application with covid19 real time data. i have used api.but i can't access json data from it. when it runs object object error is showing.here is the current output
here is the data inside the api.here is the api data.
import { Component } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs';
import { LoadingController } from '#ionic/angular';
import { finalize } from 'rxjs/operators';
import { NULL_EXPR } from '#angular/compiler/src/output/output_ast';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
data : string;
error: string;
loading: any;
obj: string;
updatedDateSL: string;
constructor(private http: HttpClient,public loadingController: LoadingController) {
this.data='';
this.error='';
this.obj='';
this.updatedDateSL='';
}
async ionViewWillEnter() {
await this.presentLoading();
// Load the data
this.prepareDataRequest()
.pipe(
finalize(async () => {
// Hide the loading spinner on success or error
await this.loading.dismiss();
})
)
.subscribe(
data=> { //data is a java script object that is why it can stringfy.
//updatedDateSL = data.data.update_date_time; // Set the data to display in the template
this.data = JSON.stringify(data); //converts to string
this.obj=JSON.parse(this.data); //info is a javascript objct
//var totCasesSL = info.data.local_total_cases;
//var totHospitalSL = data.local_total_number_of_individuals_in_hospitals;
//var totRecoverSL = data.local_recovered;
//var totDeathSL = data.local_deaths;
//var newSL = data.local_new_cases;
//var newDeathSL = data.local_new_deaths;
//var totActiveSL = data.local_active_cases;
//alert(info.update_date_time);
},
err => {
// Set the error information to display in the template
this.error = `An error occurred, the data could not be retrieved: Status: ${err.status}, Message: ${err.statusText}`;
}
);
}
async presentLoading() {
// Prepare a loading controller
this.loading = await this.loadingController.create({
message: 'Loading...'
});
// Present the loading controller
await this.loading.present();
}
private prepareDataRequest(): Observable<object> {
// Define the data URL
//const dataUrl = 'https://api.nigelbpeck.com/';
const dataUrl = 'https://hpb.health.gov.lk/api/get-current-statistical/';
// Prepare the request
return this.http.get(dataUrl);
}
}
here is the html file.
/<ion-header>
<ion-toolbar>
<ion-title>
Ionic 4 Example App
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="ion-padding">
<p>Data will be presented here...</p>
<p *ngIf="!error;else errorContent">{{ obj ? obj : '-' }}</p>
<ng-template #errorContent><p><span style="color: red;">{{error}}</span></p></ng-template>
</div>
</ion-content>
i need to get local_new_cases and local_total_cases.Api connction is working here is the event that i run application sucessfly.final sucessful output.
To show data in html you need to stringify the data so you should use data instead of obj in html . Update html code from
<ion-content>
<div class="ion-padding">
<p>Data will be presented here...</p>
<p *ngIf="!error;else errorContent">{{ obj ? obj : '-' }}</p>
<ng-template #errorContent><p><span style="color: red;">{{error}}</span></p></ng-template>
</div>
</ion-content>
to
<ion-content>
<div class="ion-padding">
<p>Data will be presented here...</p>
<p *ngIf="!error;else errorContent">{{ data ? data : '-' }}</p>
<ng-template #errorContent><p><span style="color: red;">{{error}}</span></p></ng-template>
</div>
</ion-content>
I am using Ionic2 rc4. I have a login form.
As you can see, the Sign In button is disabled.
My problem is it should only be disabled when the form is invalid. However, when the form is valid, i.e. there is an Email and Password, it should not be disabled.
When I enter an Email and Password it stays disabled, but if I switch focus off the browser, and then back to it, it is enabled. It is as if the page is not refreshing to the correct status.
Question
Is there a way to get this enabled immediately as the form is valid?
loginemail.html
<ion-header>
<ion-navbar>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>Login</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<form [formGroup]="loginForm" (ngSubmit)="submit()">
<ion-item>
<ion-label floating>Email</ion-label>
<ion-input type="text" formControlName="email" id="email" [(ngModel)]="personModel.emailAddress"></ion-input>
</ion-item>
<control-messages class="error-box" [control]="loginForm.controls.email"></control-messages>
<ion-item>
<ion-label floating>Password</ion-label>
<ion-input type="password" formControlName="password" id="password"></ion-input>
</ion-item>
<control-messages class="error-box" [control]="loginForm.controls.password"></control-messages>
<br/>
<ion-buttons>
<button ion-button class="form-button-text" type="submit" [disabled]="!loginForm.valid" block round>Sign In</button>
</ion-buttons>
</form>
<br/><br/>
<p (click)="forgotPassword()" class="small-text">Forgot email or password?</p>
<br/><br/><br/><br/>
<button ion-button color="light" (click)="register()" color="dark" clear block round class="form-button-text">Quick Sign up</button>
</ion-content>
loginemail.ts
import { Component, Input, Inject, forwardRef } from '#angular/core';
import { NavController, NavParams, ViewController, AlertController, MenuController, Events, Loading, LoadingController } from 'ionic-angular';
import { FirebaseAuth } from 'angularfire2';
import { ValidationService } from '../validation/validationService';
import { FormBuilder, FormControl, FormGroup, Validators } from '#angular/forms';
import { RegisterPage } from '../register/register';
import { ForgotPage } from '../forgot/forgot';
import { PersonModel } from '../model/personModel';
import { PersonService } from '../service/personService';
import { UtilityService } from '../utils/utilityService';
import { PersonPage } from '../person/person';
#Component({
templateUrl: 'loginemail.html'
})
export class LoginEmailPage {
public loginForm: FormGroup;
public errorMessage: string;
public personModel: PersonModel = null;
public personService: PersonService = null;
public personLoggedIn: boolean = false;
public menu: MenuController = null;
public utilityService: UtilityService = null;
public events: Events = null;
public loading: Loading = null;
public alertCtrl: AlertController = null;
public fireAuth: firebase.auth.Auth;
public userProfile: firebase.database.Reference;
#Input() control: FormControl;
constructor(#Inject(forwardRef(() => UtilityService)) utilityService, public auth: FirebaseAuth, menu: MenuController, public nav: NavController,
public navParams: NavParams, public builder: FormBuilder, public viewCtrl: ViewController, alertCtrl: AlertController,
personService: PersonService, events: Events, public loadingCtrl: LoadingController) {
this.fireAuth = firebase.auth();
this.userProfile = firebase.database().ref('/userProfile');
this.loginForm = builder.group({
'email': ['', [Validators.required, Validators.minLength(3), Validators.maxLength(55), ValidationService.emailValidator, (control) => ValidationService.personEmailNotExists(control, this.personService)]],
'password': ['', [Validators.required, Validators.minLength(5), Validators.maxLength(45), ValidationService.passwordValidator]]
});
this.alertCtrl = alertCtrl;
this.events = events;
this.utilityService = utilityService;
this.menu = menu;
this.personModel = this.navParams.get('personModel');
if (!this.personModel) {
this.personModel = new PersonModel();
}
this.personService = personService;
}
submit() {
this.loading = this.loadingCtrl.create({
content: 'Please wait...'
});
if (this.loginForm.dirty && this.loginForm.valid) {
this.loading.present().then(() => {
this.checkCredentials(this.loginForm.value.email, this.loginForm.value.password).then(() => {
if (this.personLoggedIn === true) {
this.loginFirebaseUser(this.loginForm.value.email, this.loginForm.value.password).then((authData) => {
let user: firebase.User = this.fireAuth.currentUser;
if (!user) {
this.auth.subscribe((authData) => {
this.login(authData.auth);
});
} else {
this.login(user);
}
}).catch((error) => {
console.error('Error trying to login ', error);
this.loading.dismiss().then(() => {
this.doAlert(error.message);
});
});
}
this.loading.dismiss();
});
});
}
}
login(firebaseUser: firebase.User): void {
let promise: Promise<any> = this.utilityService.login(this.personModel, firebaseUser, this.nav, this.auth, this.fireAuth, false);
if (promise) {
promise.then(() => {
let data = {
person: this.personModel
}
this.events.publish('push:notifications', data);
this.loading.dismiss().then(() => {
if (this.navParams.get('fromReview')) {
this.nav.pop();
} else if (this.navParams.get('fromChat')) {
this.nav.pop();
} else {
this.nav.setRoot(PersonPage);
}
});
}, error => {
this.utilityService.logout(this.auth, this.fireAuth).then(() => {
this.utilityService.setUpMenuItems();
this.auth.logout();
});
this.loading.dismiss().then(() => {
let alert = this.alertCtrl.create({
message: error.message,
buttons: [
{
text: "Ok",
role: 'cancel'
}
]
});
alert.present();
});
});
} else {
this.loading.dismiss();
}
}
checkCredentials(email: string, password: string): any {
let promiseUsername: Promise<PersonModel> = this.personService.getPersonByEmail(email);
return promiseUsername.then((personModel: PersonModel) => {
if (personModel.emailAddress != email) {
this.doAlert('Email does not exist.');
} else {
if (personModel.emailAddress === this.loginForm.value.email) {
this.personModel = personModel;
this.personLoggedIn = true;
} else {
this.personLoggedIn = false;
this.doAlert('Password does not match Username.');
}
}
});
}
doAlert(msg: string) {
this.loading.dismiss().then(() => {
let alert = this.alertCtrl.create({
title: 'Login',
subTitle: msg,
buttons: ['Dismiss']
});
alert.present().then(() => {
this.loading.dismiss();
});
});
}
register() {
this.nav.push(RegisterPage, {
})
}
forgotPassword() {
this.nav.push(ForgotPage, {
personModel: this.personModel
});
}
loginFirebaseUser(email: string, password: string): firebase.Promise<boolean> {
return this.fireAuth.signInWithEmailAndPassword(email, password).then(() => {
console.log('signInWithEmailAndPassword', email, password);
}).catch((error)=> {
console.error('Error signInWithEmailAndPassword', email, password, error.name, error.message);
throw new Error(error.message);
});
}
}
UPDATE
As per advise below, I have tried wrapping the firebase call in a Promise, but this makes no difference unfortunately.
return new Promise<any>(() => {
this.loginFirebaseUser(this.loginForm.value.email, this.loginForm.value.password).then((authData) => {
let user: firebase.User = this.fireAuth.currentUser;
if (!user) {
this.auth.subscribe((authData) => {
this.login(authData.auth);
});
} else {
this.login(user);
}
}).catch((error) => {
console.error('Error trying to login ', error);
this.loading.dismiss().then(() => {
this.doAlert(error.message);
});
});
});
Try setting a name to your email and password field
<ion-input type="text" formControlName="email" id="email" name="email" [(ngModel)]="personModel.emailAddress"></ion-input>
<ion-input type="password" formControlName="password" name="password" id="password"></ion-input>
That way loginForm has references to those elements for it's validtion.
I was having the same problem.
Looks like using firebase along with Ionic 2 breaks forms, inputs, buttons, etc.
I've already opened a github issue for this and i'm not the first one.
What i've done as a workaround is encapsulate every call to firebase within a promisse (see the link for an example) and it solved for me. There is some issues with using auth.onAuthStateChangedin app.components too, i haven't tried, but maybe putting it inside a Observable may be a goof ideia for this too.
So, the problem is using the firebase promisses along with ionic2/angular2, the typescript promisses works fine and doesn't breaks you app.