I created an angular material custom date picker control, it is working and able select and update the date but when I tried to edit the input box it was not allowed. always it is readonly
Below is the code for reference. Can someone suggest this?
import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '#angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor} from '#angular/forms';
import { MatDatepickerInputEvent } from '#angular/material/datepicker';
import { formatDate } from '#angular/common';
import { DateAdapter, MAT_DATE_FORMATS, NativeDateAdapter } from '#angular/material/core';
type Value=number;
export const PICK_FORMATS = {
parse: {dateInput: {month: 'short', year: 'numeric', day: 'numeric'}},
display: {
dateInput: 'input',
monthYearLabel: {year: 'numeric', month: 'short'},
dateA11yLabel: {year: 'numeric', month: 'long', day: 'numeric'},
monthYearA11yLabel: {year: 'numeric', month: 'long'}
}
};
class PickDateAdapter extends NativeDateAdapter {
format(date: Date, displayFormat: Object): string {
if (displayFormat === 'input') {
return formatDate(date,'MM/dd/yyyy',this.locale);;
} else {
return date.toDateString();
}
}
}
#Component({
selector: 'app-date',
templateUrl: './date.component.html',
styleUrls: ['./date.component.css'],
providers:[
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(()=>DateComponent),
multi:true
},
{provide: DateAdapter, useClass: PickDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: PICK_FORMATS}
]
})
export class DateComponent implements OnInit,ControlValueAccessor {
value: Value;
isDisable:boolean;
#Input() placeholder:string;
#Input() min: Date;
#Input() max:Date;
#Output() changed = new EventEmitter<Value>();
constructor() { }
ngOnInit(): void {
}
get inputValue():Date{
return this.value ? new Date(this.value):null;
}
private propagateChange: any = () =>{ };
private propagateTouched: any = () =>{ };
writeValue(value: Value): void {
this.value=value
}
registerOnChange(fn: any): void {
this.propagateChange=fn;
}
registerOnTouched(fn: any): void {
this.propagateTouched=fn;
}
setDisabledState(isDisabled: boolean): void {
this.isDisable=isDisabled;
}
onChanged( event:MatDatepickerInputEvent<Date>):void{
const value=event.value ? event.value.getTime():null;
this.value=value;
this.propagateChange(value);
this.changed.emit(value);
}
OnClosed():void{
this.propagateTouched();
}
}
// Custome Control HTML
<div>
<input type="text"
[matDatepicker]="picker"
(dateChange)="onChanged($event)"
(click)="picker.open()"
[attr.disabled]="isDisable ? true : null"
[value]="inputValue" [min]="min" [max]="max"
placeholder="{{placeholder || 'Choose a date '}}"
>
<mat-datepicker-toggle matSuffix [for]="picker" [disabled]="isDisable"></mat-datepicker-toggle>
<mat-datepicker #picker (closed)="OnClosed()"></mat-datepicker>
</div>
//custom field
<app-date formControlName="Activedate" placeholder="Date" ></app-date>
I created an angular material custom date picker control, it is working and able select and update the date but when I tried to edit the input box it was not allowed. always it is readonly
Below is the code for reference. Can someone suggest this?
Thanks in advance
Related
Update 1: ============
After remove "window.ShadyDOM={force:true};" then it worked. But this is causing other problem ;):
https://vaadin.com/forum/thread/17399734/leverage-browser-save-password-feature
#Override
public void configurePage(InitialPageSettings settings) {
// TODO Auto-generated method stub
settings.addMetaTag("mobile-web-app-capable", "yes");
settings.addMetaTag("apple-mobile-web-app-capable", "yes");
settings.addMetaTag("apple-mobile-web-app-status-bar-style", "black");
settings.addInlineWithContents(
InitialPageSettings.Position.PREPEND, "window.customElements=window.customElements||{};"
+ "window.customElements.forcePolyfill=true;" + "window.ShadyDOM={force:true};",
InitialPageSettings.WrapMode.JAVASCRIPT);
}
End Update. ============
I am trying to integrate Payal checkout to Vaadin 14.7 (Spring core, not spring boot).
Here is paypal-view.js
import { LitElement, html, css } from "lit-element";
let buttons;
let hasRendered = false;
class PaypalElement extends LitElement {
static get properties() {
return {
mood: {
type: String,
noAccessor: false,
hasChanged(newVal, oldVal) {
console.log("newVal " + newVal + " oldVal " + oldVal);
},
},
};
}
static get styles() {
return [
css`
mood_color {
color: green;
}
#paypal-button {
size: "responsive";
}
`,
];
}
firstUpdated(_changedProperties) {
let testFname = this.shadowRoot.getElementById("fname");
super.firstUpdated(_changedProperties);
if (buttons && buttons.close && hasRendered) {
buttons.close();
hasRendered = false;
}
buttons = window.paypal.Buttons({
// Set up the transaction
createOrder: function (data, actions) {
return actions.order.create({
application_context: {
brand_name: "Brand name",
user_action: "PAY_NOW",
//No shipping for in-tangible merchant
shipping_preference: "NO_SHIPPING",
payment_method: {
payee_preferred: "IMMEDIATE_PAYMENT_REQUIRED", // Pending status transactions will not be allowed if you pass this parameter.
payer_selected: "PAYPAL",
},
},
purchase_units: [
{
soft_descriptor: "CC_STATEMENT_NAME",
amount: {
value: "5.00",
},
},
],
});
},
// Finalize the transaction
onApprove: function (data, actions) {
const elementText = document.getElementById("fname");
return actions.order.capture().then(function (orderData) {
// Successful capture! For demo purposes:
console.log(
"Capture result",
orderData,
JSON.stringify(orderData, null, 2)
);
let transaction = orderData.purchase_units[0].payments.captures[0];
// Replace the above to show a success message within this page, e.g.
// const element = document.getElementById('paypal-button-container');
// element.innerHTML = '';
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
document.getElementById("update-paypal-trans").innerHTML =
"update-paypal-trans = " + transaction.id;
// trigger lit event
testFname.value = transaction.id;
testFname.click();
document.getElementById("paypalelement").remove();
//console.log(elementText);
});
},
onError: function (error) {
console.log("onError", error, JSON.stringify(error, null, 2));
},
onCancel: function (data, actions) {
console.log("onCancel", data, JSON.stringify(data, null, 2));
document.getElementById("update-paypal-trans").innerHTML =
"testing 123";
// update shadow element
testFname.value = "12345 " + actions;
// trigger lit event
testFname.click();
},
});
// load paypal buttons and put them to element id="paypal-button-to-display" which is shadow dom
buttons
.render(this.shadowRoot.getElementById("paypal-button-to-display"))
.then(() => {
hasRendered = true;
})
.catch((err) => {
console.log(err)
// not mounted anymore, we can safely ignore the error
return;
});
}
// outside updates shadow element
updateShadow() {
this.shadowRoot.getElementById("test-update-shadow").innerHTML =
"test update shadow trans";
this.mood = "nice";
}
updateTask(e) {
console.log("updateTask: " + e);
}
updateTaskClick(e) {
console.log("updateTaskClick: " + e);
// call back-end
}
render() {
return html`
Web Components are
<span class="mood_color"> ${this.mood} and ${this.innerHTML}</span>!
<input
type="text"
id="fname"
name="fname"
value="${this.mood}"
#change=${(e) => this.updateTask(e.target.value)}
#click="${(e) => this.updateTaskClick(e.target.value)}"
/>
<div id="paypal-button-to-display"></div>
<br />
<div id="test-update-shadow">test-update-shadow-default</div>
<br />
<input
#click="${() => this.updateShadow()}"
id="myinput"
type="button"
value="update shadow button"
/>
`;
}
attributeChangedCallback(name, oldval, newval) {
super.attributeChangedCallback(name, oldval, newval);
console.log("attribute change: ", name, newval);
}
changeProperties() {
let randomString = Math.floor(Math.random() * 100).toString();
this.mood = "myProp " + randomString;
console.log("randomString change: ", randomString);
}
}
customElements.define("paypal-element", PaypalElement);
hello-world-view.ts
import { html, LitElement, customElement } from 'lit-element';
import './paypal-view';
import '#vaadin/vaadin-button';
import '#vaadin/vaadin-text-field';
#customElement('hello-world-view')
export class HelloWorldView extends LitElement {
createRenderRoot() {
// Do not use a shadow root
return this;
}
constructor() {
super();
}
render() {
return html`
<vaadin-text-field id="name" label="Your name"></vaadin-text-field>
<vaadin-button >Say hello</vaadin-button>
<paypal-elementt mood="great" id="paypalBut">hello customer</paypal-elementt>
`;
}
}
hello-world-view.ts
package com.lecompany.iad.view;
import com.lecompany.iad.app.MainView;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.littemplate.LitTemplate;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.template.Id;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouteAlias;
/**
* A Designer generated component for the stub-tag template.
*
* Designer will add and remove fields with #Id mappings but does not overwrite
* or otherwise change this file.
*/
#PageTitle("Hello World")
#Route(value = "hello", layout = MainView.class)
#Tag("hello-world-view")
#JsModule("./src/view/hello-world-view.ts")
public class HelloWorldView extends LitTemplate {
#Id
private TextField name;
// #Id
// private Button sayHello;
public HelloWorldView() {
UI.getCurrent().getPage().addJavaScript("https://www.paypal.com/sdk/js?client-id=AejZZjQsvxS299I2_LSnRkJStp0AsBzScCqbGK1_W6RNJssNR5NVnKYd97dM2kOJnRMF1u1ldLGjOlZ5¤cy=USD");
// sayHello.addClickListener(e -> {
// Notification.show("Hello " + name.getValue());
// });
}
}
And here is error:
I tested above codes in Spring boot, then it works fine.
but it got error in the normal spring code. Any advice on this ?
There is reported issue for Paypal.
Paypal reported issue
It is a Vaadin bug and reported here:
Vaadin bug
I have problem when custom using mat-radio-group and mat-radio-button in Angular 12.
I have my-radio-group that wrap mat-radio-group and some my-radio-button as the ContentChildrens,
my-radio-button component wrap mat-radio-button.
But i cannot use ngModel to binding and handle change event when select radio.
It used to work well in Angular 7 before.
Can anyone help me this issue?
Sorry if my english is not quite good,
Thank you so much :)
My code here:
app.component.ts
_selection: any = 1;
get selection() {
return this._selection;
}
set selection(val: any) {
this._selection = val;
}
onChange($event: any): void {
}
app.component.html:
<my-radio-group [(ngModel)]="selection" (change)="onChange($event)">
<br/>
<my-radio-button [value]="1">Radio 1</my-radio-button>
<br/>
<my-radio-button [value]="2">Radio 2</my-radio-button>
<br/>
<my-radio-button [value]="3">Radio 3</my-radio-button>
<br/>
<my-radio-button [value]="4">Radio 4</my-radio-button>
</my-radio-group>
my-radio-group.component.ts:
export const MY_RADIO_GROUP_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MyRadioGroupComponent),
multi: true
};
#Directive({
selector: "my-radio-group",
providers: [
MY_RADIO_GROUP_CONTROL_VALUE_ACCESSOR,
{provide: MatRadioGroup, useExisting: MyRadioGroupComponent}
]
})
export class MyRadioGroupComponent extends MatRadioGroup {
}
my-radio-button.component.ts
#Component({
selector: "my-radio-button",
templateUrl: "./my-radio-button.component.html"
})
export class MyRadioButtonComponent {
#Input() value: any;
#Input() disabled: boolean | undefined;
}
my-radio-button.component.html
<mat-radio-button [value]="value" [disabled]="disabled">
<ng-content></ng-content>
</mat-radio-button>
I have built a geolocation service that I wish to use the getUserPosition() method on the home.page
location.service.ts
import { Injectable } from '#angular/core';
import { Geolocation, GeolocationOptions, Geoposition, PositionError } from '#ionic-native/geolocation/ngx';
#Injectable({
providedIn: 'root'
})
export class LocationService {
options: GeolocationOptions;
currentPos: Geoposition;
loc: any;
constructor( private geolocation: Geolocation ) { }
getUserPosition() {
return new Promise((resolve, reject) => {
this.options = {
maximumAge: 3000,
enableHighAccuracy: true
};
this.geolocation.getCurrentPosition(this.options).then((pos: Geoposition) => {
this.currentPos = pos;
const location = {
lat: pos.coords.latitude,
lng: pos.coords.longitude,
time: new Date(),
};
console.log('loc', location);
resolve(pos);
}, (err: PositionError) => {
console.log("error : " + err.message);
reject(err.message);
});
});
}
}
I access the service in my home.page
home.ts
import { Component, OnInit } from '#angular/core';
import { LocationService } from '../../services/geolocation/location.service';
#Component({
selector: 'app-home',
templateUrl: './home.page.html',
styleUrls: ['./home.page.scss'],
})
export class WorkalonePage implements OnInit {
getPosition: any;
constructor(
private LocationService: LocationService
) {}
ngOnInit() {
this.getPosition = this.LocationService.getUserPosition;
}
}
home.html
<ion-content>
<ion-button expand="full" color="primary" (click)="getUserPosition()">Get Location Sevice</ion-button>
</ion-content>
but when I click on (click)="getUserPosition()" on my html I get the error getUserPosition() is not a function. I have have been looking online for answers, but all answers involve using the geolocation in the home.ts file. Any help would be greatly appreciated.
From what I see in home.ts, you haven't defined a function named getUserPosition.
Add something along the lines of what's below to home.ts:
getUserPosition() {
this.LocationService.getUserPosition().then((pos) => {
this.getPosition = pos;
});
}
You can directly call your service method in html like this
LocationService.ts
getUserPosition() {
this.LocationService.getUserPosition().then((pos) => {
this.getPosition = pos;
});
}
Define service object in home.ts
constructor(public ls:LocationService){}
At home.html
<ion-button expand="full" color="primary" (click)="ls.getUserPosition()">
Get Location Sevice
</ion-button>
I'm using angular 2 and in this part (home page) I have a google autocomplete place input that if you click it goes another page(map) and it shows the map with that latitude and longitude user clicked previous page. However the point is I want in the URL, lat and long will be shown.It's complicated for me and don't know what to do,also I have read https://angular.io/tutorial/toh-pt5#parameterized-route but didn't understand.
app-routing.module:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { HomeComponent } from './home/home.component';
import { MapComponent } from './search/map.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'map/'+this.latitude+','+this.longitude, component:
MapComponent },
];
#NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
in the path I wrote like this but don't know is correct or not.
home.html:
<div class="col-md-8 col-md-push-2 container search-location">
<div class="form-group">
<input id="search" placeholder="select place"
autocorrect="off" autocapitalize="off" spellcheck="off" type="text"
class="form-control"
#search [formControl]="searchControl">
</div>
</div>
home.component.ts:
import { Component, ElementRef, NgModule, NgZone, OnInit, ViewChild } from
'#angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from
"#angular/forms";
import { BrowserModule } from "#angular/platform-browser";
import { AgmCoreModule, MapsAPILoader } from '#agm/core';
import { Router } from '#angular/router';
import {} from '#types/googlemaps';
declare let google: any;
import 'rxjs/add/observable/of';
#Component({
selector: 'home-search',
templateUrl: './home-search.html',
styles: [`
agm-map {
height: 300px;
}
`],
})
export class HomeSearchComponent implements OnInit {
public google:any;
public latitude: number;
public longitude: number;
public searchControl: FormControl;
public zoom: number;
#ViewChild("search")
public searchElementRef: ElementRef;
constructor(
private mapsAPILoader: MapsAPILoader,
private ngZone: NgZone,
private router:Router,
) {}
ngOnInit() {
let options = {
types: ["address"],
componentRestrictions: {country: "ir"}
};
//set google maps defaults
this.zoom = 4;
this.latitude = 39.8282;
this.longitude = -98.5795;
//create search FormControl
this.searchControl = new FormControl();
//set current position
this.setCurrentPosition();
//load Places Autocomplete
this.mapsAPILoader.load().then(() => {
let autocomplete = new
google.maps.places.Autocomplete(this.searchElementRef.nativeElement,
{options});
autocomplete.addListener("place_changed", () => {
this.ngZone.run(() => {
//get the place result
let place: google.maps.places.PlaceResult = autocomplete.getPlace();
//verify result
if (place.geometry === undefined || place.geometry === null) {
return;
}
//set latitude, longitude and zoom
this.latitude = place.geometry.location.lat();
this.longitude = place.geometry.location.lng();
this.zoom = 12;
this.router.navigate(['/map/'+this.latitude+','+this.longitude]);
});
});
});
}
private setCurrentPosition() {
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
this.zoom = 12;
});
}
}
}
map.html:
<div class="col-md-8 col-md-push-2 container search-location">
<agm-map [latitude]="latitude" [longitude]="longitude" [scrollwheel]="true"
[zoom]="zoom">
<agm-marker [latitude]="latitude" [longitude]="longitude"></agm-marker>
</agm-map>
</div>
map.component.ts:
import { Component, ElementRef, NgModule, NgZone, OnInit, ViewChild } from
'#angular/core';
import { FormControl, FormsModule, ReactiveFormsModule } from
"#angular/forms";
import { BrowserModule } from "#angular/platform-browser";
import { AgmCoreModule, MapsAPILoader } from '#agm/core';
import { Router } from '#angular/router';
import {} from '#types/googlemaps';
declare let google: any;
#Component({
selector: 'map',
templateUrl: './map.html',
styles: [`
agm-map {
height: 300px;
}
`],
})
export class MapComponent implements OnInit{
private google:any;
private latitude: number;
private longitude: number;
private searchControl: FormControl;
private zoom: number;
ngOnInit(){
}
}
It relates to parameters but I don't know how to write the code.
Could you please help me,I'm confused.
Thank you.
I'm using angular 2, firebase and ng2-highcharts.
I assign data after I receive them from firebase like so :
this.items = af.database.list('/items');
this.optionsAsync = this.items.map(data => {
this.options.series[0].data = data.map(item => ([item.x, item.y]));
return this.options;
});
Then in my view template I have :
<div [ng2-highcharts]="optionsAsync | async"></div>
This is working fine at first load. But unfortunately when new data are received chart is not updated. Any idea ?
I found a solution by referencing highcharts component with #ViewChild like so :
in component class :
import { ViewChild, Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
directives: [Ng2Highcharts]
})
export class AppComponent {
#ViewChild(Ng2Highcharts)
chartElement: Ng2Highcharts;
private chartData = {
chart: {
zoomType: 'x'
},
colors: ['rgba(255,0,255,1)'],
title: {
text: 'Items'
},
credits: '',
series: [{
type: 'area',
name: 'Items',
data: []
}]
};
chartData$ = new Subject();
ngOnInit() {
this.items.subscribe((data: any) => {
this.chartData.series[0].data = data.map(item => ([item.x, parseFloat(item.y)]) );
this.chartData$.next(this.chartData);
if(this.chartElement && this.chartElement.chart) {
var serieRef = this.chartElement.chart.series[0];
serieRef.setData(this.chartData.series[0].data);
}
});
}
}