Having two custom widget in one form in Django - forms

First let me tell I am new to Django, CSS and all web (front, back) stuff.
I am using 2 custom widget in my form
from tempus_dominus.widgets import DatePicker, TimePicker
from mapwidgets.widgets import GooglePointFieldWidget
both of them need to add below line in header of html file.
{{ form.media }}
when I just have Date picker and Time picker they are working just fine. but when I add map widget to the form only map is working. I don't know what is this and how I can solve this. if you need more information let me know.
my model class:
from django.contrib.gis.db import models
from django.contrib.gis.geos import Point
DEFAULT_LOCATION_POINT = Point(-104.9903, 39.7392)
class Event(models.Model):
latlng = models.CharField(max_length=255)
location = models.PointField(help_text="Use map widget for point the house location")
description = models.CharField(max_length=255)
date = models.DateField()
time = models.TimeField()
title = models.CharField(max_length=255)
def __str__(self):
return self.latlng
My form class:
from django import forms
from tempus_dominus.widgets import DatePicker, TimePicker
from mapwidgets.widgets import GooglePointFieldWidget
from . import models
class EventForm(forms.ModelForm):
class Meta:
model = models.Event
fields = ("location", "latlng", "date", "time", "title", "description")
widgets = {
'location': GooglePointFieldWidget,
'latlng': forms.TextInput(attrs={'class': 'form-control', 'placeholder': "LatLng"}),
'date': DatePicker(attrs={'class': 'form-control', 'placeholder': "Date"}),
'time': TimePicker(attrs={'class': 'form-control', 'placeholder': "Time"}),
'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Title"}),
'description': forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Description"}),
}
I have no idea what to try.

Related

Angular - syncfusion ejs autocomplete selecting incorrect value

Using a Syncfusion EJS Autocomplete element in a search box.
The issue being reported is that the user is not able to select the value searched
I know the issue, is because the data passed to the AutoComplete has some duplicate values, but they are distinct based on a second value.
The code below hopefully show the issue
<div class="control-section" style="margin:130px auto;width:300px">
<ejs-autocomplete
id="sample-list"
#sample
[dataSource]="countriesData"
[autofill]="isBool"
[fields]="fields"
(select)='selectIssuer($event)'
filterType="Contains"
>
<ng-template #itemTemplate let-data>
<!--set the value to itemTemplate property-->
<div class='item'>
<div>{{data.Name}} -- {{data.Structure != 'SPV' ? 'BT' : data.Structure}}</div>
</div>
</ng-template>
</ejs-autocomplete>
</div>
/**
* AutoComplete Highlight Sample
*/
import { Component, ViewChild } from '#angular/core';
import { AutoCompleteComponent } from '#syncfusion/ej2-angular-dropdowns';
#Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.css'],
})
export class AppComponent {
public countriesData = [
{ Name: 'Client 1' , Id: 'A3D49279-18DC-40FB-B843-B6207518B379', Structure: 'BT'},
{ Name: 'Client 1' , Id: '77ED2BD8-2309-4792-9264-01DEAFC3227E', Structure: 'SPV'},
{ Name: 'Client 2' , Id: 'BA017D4F-DD5C-4F2D-852C-DD17AF209436', Structure: 'BT'},
{ Name: 'Client 3' , Id: '78FCDCB9-06EA-4D9B-A352-171B1594AE24', Structure: 'SPV'},
{ Name: 'Client 4' , Id: '48C3168A-FA2A-4EF7-B184-61F18C47AB6D', Structure: 'BT'},
{ Name: 'Client 4' , Id: 'E734CA83-91FF-4475-B35E-BE232ACBF137', Structure: 'SPV'}
];
public fields: Object = { value: 'Name' };
public isBool: Boolean = true;
}
selectIssuer(_issuer: any) {
this.getSearchIssuer.emit({ issuer: <CombinedIssuer>_issuer.itemData, clear: false });
}
AS is visible, some of the Client Names are the same, but what makes them distinct is the combination with the Structure.
The issue is that when a user selects say Client 4 that has an SPV Structure, it still loads the Client 4 with the BT structure.
Is it possible for the EJS Autocomplete to take in to consideration the combination of fields to make sure the correct item is selected or is is possible for the EJS Autocomplte to use the Item Id as well
Can it be possible to pass in the Id value to the Fields property ?
I was able to figure this out, so sharing my findings:
The additional code is shown below with ...
<ejs-autocomplete id='combinedIssuerSearch' #searchCombinedIssuers
[dataSource]='ixDispalyCombinedIssuerList'
[fields]='issuerFields'
ShowBorder='False'
(select)='selectIssuer($event)'
[placeholder]='defaultText'
[filterType]='issuerFilterType'
*(filtering)='onFiltering($event)'*
[showClearButton]="false"
class="auto-complete-search">
<ng-template #itemTemplate let-data>
<!--set the value to itemTemplate property-->
<div class='item'>
<div class='issuer-name'> {{data.Name}}</div>
<div class="ls_spv">{{data.Structure != 'SPV' ? 'BT' : data.Structure}}</div>
</div>
</ng-template>
</ejs-autocomplete>
in the ts file I added code to handle the OnFiltering event
onFiltering(args) {
args.preventDefaultAction = true;
var predicate = new Predicate('Name', 'contains', args.text, true);
predicate = predicate.or('Structure', 'contains', args.text, true);
var query = new Query();
query = args.text != '' ? query.where(predicate) : query;
args.updateData(this.ixDispalyCombinedIssuerList, query);
}

Mapbox auto fill complete address

I use mapbox tools for my autofill place address autocomplete on my project Symfony
I want to know how can i extract full complete address in autofill, i have 2 inputs one for search and one hidden for get full/complete address
<mapbox-address-autofill>
{{ form_widget( form.address, {
'attr': {
'class': 'form-control form-control-solid font-weight-bold',
'placeholder': 'Adresse de départ',
'required': 'required',
'autocomplete': 'address-line1'
}
} ) }}
{{ form_widget( form.address_value, {
'attr': {
'autocomplete': 'full-address'
}
}) }}
</mapbox-address-autofill>
I have this but with tag 'full-addresse' 'complete' 'place_name'
No one workn if you have any solution for get full address to persist this in php Symfony project
"full_address" is a property of the feature object that is returned from a retrieve event, but does not automatically map to any HTML form field autocomplete value. The only object properties that get mapped to HTML elements are the ones corresponding to WHATWG standards, i.e.:
'street-address'
'address-line1'
'address-line2'
'address-line3'
'address-level1'
'address-level2'
'address-level3'
'address-level4'
'country'
'country-name'
'postal-code'
I'm not familiar with PHP, but a way to do this in Javascript would be something like:
const autofill = document.querySelector('mapbox-address-autofill');
const targetInput = document.getElementById('myTargetInput');
autofill.addEventListener('retrieve', (event) => {
const featureCollection = event.detail;
const feature = featureCollection[0];
const fullAddress = feature.properties.full_address;
targetInput.value = fullAddress;
});

ReactJs MaterialUI - How do I test change of a select component (non-native)?

I have this simple component in my app:
import {Select, MenuItem} from '#material-ui/core';
import {useEffect, useState} from 'react';
export const CountrySelection = ({
countries,
selectedCountry,
onChange,
id,
className = ''
})=>{
const [_selectedCountry, _setSelectedCountry] = useState(null);
useEffect(()=>{
_setSelectedCountry(selectedCountry);
}, [selectedCountry]);
return(
<Select
value={(_selectedCountry && _selectedCountry.label) || ''}
onChange={onChange}
id={id}
className={'selection ' + className}
inputProps={{
'data-testid':'country-selection'
}}
>
{countries.map((c)=><MenuItem
key={c.id}
value={c.label}
>{c.label}</MenuItem>
)}
</Select>
)
}
This is my test attempt. I want to test that component keeps correct value/visual state when I change to a different option in the Select component:
afterEach(cleanup);
const setup = () => {
const countries = [
{label: "Austria", id: 0, code: 'at'},
{label: "Denmark", id: 1, code: 'dk'},
{label: "Germany", id: 2, code: 'de'}
];
const defaultCountry = countries[0];
const utils = render(
<CountrySelection
countries={countries}
selectedCountry={defaultCountry}
id="country-selection"
onChange={()=>{}}
/>
);
return {
...utils,
}
}
test('country selection has correct number of options', async()=>{
const {getAllByRole, getByText, getByTestId} = setup();
const selectEl = document.querySelector('#country-selection');
fireEvent.mouseDown(selectEl);
const options = getAllByRole('option');
expect(options.length).toBe(3);
const choice2 = getByText('Denmark');
expect(choice2.innerHTML).toBe('Denmark<span class="MuiTouchRipple-root"></span>');
const choice3 = getByText('Germany');
expect(choice3.innerHTML).toBe('Germany<span class="MuiTouchRipple-root"></span>');
// how to change the value and query it?
fireEvent.click(choice3);
const selection = getByTestId('country-selection');
expect(selection.value).toBe('Germany'); // doesn't work, value is still "Austria"
})
How do I do this with Select component? I cannot use native={true} prop.
(I am typing here just so that Stack overflow posting validation is happy with ratio of code to other text. I will type as long as it doesn't let me post my question. Sorry, humans.)
If you just want to check if a country has been selected correctly you can use userEvent to select the option like a real user would:
import { screen } from '#testing-library/react';
test('country selection has correct number of options', async()=>{
// Check that the correct number of options are displayed
const options = screen.getAllByRole('option');
expect(options.length).toBe(3);
// Select Denmark
userEvent.selectOptions(screen.getByRole('combobox'), 'dk');
// Check that Denmark is the selected country
expect((screen.getByText('Denmark') as HTMLOptionElement).selected).toBe(true);
// Select Germany
userEvent.selectOptions(screen.getByRole('combobox'), 'de');
// Check that Germany is now the selected country
expect((screen.getByText('Denmark') as HTMLOptionElement).selected).toBe(true);
})

Customize tcomb-form-native's data filds

I'm trying to customize the Data field of atcomb-form-native module.
I wish the date fields were a classic input field but I still tried different methods, I didn't succeed.
I tried to override the datepicker field style but put the style when opening the picker to insert the date and not around the message.
Instead of 'Tap here to select a date' I would like to insert a phrase at will. How can I do?
Also, how can I customize the date format? I tried following this issue of github but it didn't solve the problem.
This is the part of code for formatting the data:
config: {
format: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
dateFormat: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
timeFormat: date => {
let toBeFormatted = new Date(date);
return String('Valida dal' + toBeFormatted.format('DD/MM/YYYY'));
},
}
Okay. I can give you my code. I had a little trouble finding it, but finally, everything is in the tcomb documentation.
The two important points to answer your question are :
"defaultValueText" and "format: (date) => ..."
import React, { Component } from "react";
import Expo from "expo";
import t from "tcomb-form-native";
import moment from 'moment';
import { StyleSheet, Text, Date} from "react-native";
import { Button } from "react-native-elements";
const Form = t.form.Form;
Form.stylesheet.dateValue.normal.borderColor = '#d0d2d3';
Form.stylesheet.dateValue.normal.backgroundColor = '#ffffff';
Form.stylesheet.dateValue.normal.borderRadius= 5,
Form.stylesheet.dateValue.normal.color = 'grey';
Form.stylesheet.dateValue.normal.borderWidth = 1;
const User = t.struct({
pseudo: t.String,
birthday: t.Date,
});
const options = {
order: ['pseudo','birthday'],
fields: {
pseudo: {
placeholder: 'Enter Name',
error: 'Name is empty?',
},
birthday: {
mode: 'date',
label: 'birthday',
config: {
defaultValueText: 'Enter birthday', // Allows you to format the PlaceHolders !!
format: (date) => {
return moment(date).format('DD-MM-YYYY'); // Allows you to format the date !!
},
}
},
},
};
... ...
export default class SignUp extends Component {
state = {...
render() {
return (
<View style={styles.container}>
<Form
type={User}
ref={c => (this._form = c)} // assign a ref
options={options} //set form options
/>
<Button
title="Sign Up!"
buttonStyle={styles.button}
onPress={this.handleSubmit}
/>
</View>
);
}
}
} ...

How to format data before displaying it on ag-grid

I've just discovered ag-grid. I'm using it on angular2+ and loading data from api. One of fields is date, but its in ISO format. I've been trying to format it, is there any way to do it, is it possible to add pipe or some other way? Usually i do it like this {{ someISODate | date: 'dd.MM.yyyy HH:mm'}}. Do i really have to format it manually in component before displaying it? Also I was wondering if its possible to add two fields under one column. Why? Well i have column author, and in data that im getting from api i have author.firstname and author.lastname, and now I wanna display both fields in same column. Any hints or examples are more than welcomed.
columnDefs = [
{headerName: 'Datum kreiranja', field: 'createdAt' }, //<-- wanna format it
{headerName: 'Vrsta predmeta', field: 'type.name' },
{headerName: 'Opis', field: 'description'},
{headerName: 'Kontakt', field: 'client.name'},
{headerName: 'Autor', field: 'author.firstname'}, //<-- wanna display author.lastname in same cell
{headerName: 'Status', field: 'status.name'}
];
You can do this by using cellRenderer (or valueFormatter as pointed in the UPDATE) and moment library.
{
headerName: 'Datuk kreiranja', field: 'createdAt',
cellRenderer: (data) => {
return moment(data.createdAt).format('MM/DD/YYYY HH:mm')
}
}
If you don't want to use moment, then below is how you can do it.
cellRenderer: (data) => {
return data.value ? (new Date(data.value)).toLocaleDateString() : '';
}
For Author field as well,
cellRenderer: (data) => {
return data.author.firstname + ' ' + data.author.lastname;
}
Reference: ag-grid: Cell Rendering
UPDATE
As suggested by #Mariusz, using valueFormatter makes more sense in this scenario. As per documentation, Value Formatter vs Cell Renderer
value formatter's are for text formatting and cell renderer's are for
when you want to include HTML markup and potentially functionality to
the cell. So for example, if you want to put punctuation into a value,
use a value formatter, but if you want to put buttons or HTML links
use a cell renderer.
You can use valueFormatter
{headerName: 'Datuk kreiranja', field: 'createdAt', valueFormatter: this.dateFormatter},
Create a small function:
dateFormatter(params) {
return moment(params.value).format('MM/DD/YYYY HH:mm');
}
First of all thanks to Paritosh.
The issue I was facing is the date field I was receiving from API is on the below format
"endDateUTC":"2020-04-29T12:00:00",
I have followed Paritosh solution using cellrenderer along with moment library but the value was always formatted to today's date for some reason.
The below solution is using valueFormatter with moment library.
This is for Angular2+ version. The job is really simple
In your .ts file:
import * as moment from 'moment';
{
headerName: 'End Date',
field: 'endDateUTC',
minWidth: 80,
maxWidth: 100,
valueFormatter: function (params) {
return moment(params.value).format('D MMM YYYY');
},
},
And the output you will get is:
End date:
29 APR 2020
Please feel free to change the date format you need.
Hope this will be helpful to some one.
I just want to expand on Vishwajeet's excellent answer from April 2019. Here's how I would use his code, and which import commands would be required:
import { Component, OnInit, ViewChild, LOCALE_ID, Inject } from '#angular/core';
constructor(#Inject(LOCALE_ID) private locale: string)
{
}
columnDefs = [
{ headerName: 'Last name', field: 'lastName' },
{ headerName: 'First name', field: 'firstName' },
{ headerName: 'DOB', field: 'dob', cellRenderer: (data) => { return formatDate(data.value, 'd MMM yyyy HH:mm', this.locale); }},
{ headerName: 'Policy start', field: 'policyStartDate', cellRenderer: (data) => { return formatDate(data.value, 'd MMM yyyy HH:mm', this.locale); } },
{ headerName: 'Policy end', field: 'policyEndDate', cellRenderer: (data) => { return formatDate(data.value, 'd MMM yyyy HH:mm', this.locale); } }
]
And your agGrid would contain something like this:
<ag-grid-angular
class="ag-theme-material"
[rowData]="rowData"
[columnDefs]="columnDefs"
</ag-grid-angular>
This works really nicely, but I decided to move the date formatting into it's own cell renderer for a few reasons:
The code above will display null values as "1 Jan 1970 01:00"
You would need to repeat this code, plus the imports and #Inject, into any control which uses it.
It repeats the logic each time, so if you wanted to change the date format throughout your application, it's harder to do. Also, if a future version of Angular broke that date formatting, you'd need to apply a fix for each occurrence.
So, let's move it into it's own cell renderer.
My DateTimeRenderer.ts file looks like this:
import { Component, LOCALE_ID, Inject } from '#angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';
import { ICellRendererParams } from 'ag-grid-community';
import { formatDate } from '#angular/common';
#Component({
selector: 'datetime-cell',
template: `<span>{{ formatTheDate(params.value) }}</span>`
})
export class DateTimeRenderer implements ICellRendererAngularComp {
public params: ICellRendererParams;
constructor(#Inject(LOCALE_ID) public locale: string) { }
agInit(params: ICellRendererParams): void {
this.params = params;
}
formatTheDate(dateValue) {
// Convert a date like "2020-01-16T13:50:06.26" into a readable format
if (dateValue == null)
return "";
return formatDate(dateValue, 'd MMM yyyy HH:mm', this.locale);
}
public onChange(event) {
this.params.data[this.params.colDef.field] = event.currentTarget.checked;
}
refresh(params: ICellRendererParams): boolean {
return true;
}
}
In my app.module.ts file, I need to import this Component:
import { DateTimeRenderer } from './cellRenderers/DateTimeRenderer';
#NgModule({
declarations: [
AppComponent,
DateTimeRenderer
],
imports: [
BrowserModule,
AgGridModule.withComponents([DateTimeRenderer])
],
providers: [],
bootstrap: [AppComponent]
})
And now, back in my Component which uses the agGrid, I can remove LOCALE_ID, Inject from this line:
import { Component, OnInit, ViewChild, LOCALE_ID, Inject } from '#angular/core';
..remove it from our constructor...
constructor()
{
}
..import our new renderer...
import { DateTimeRenderer } from './cellRenderers/DateTimeRenderer';
..and change the columnDefs to use the new renderer:
columnDefs = [
{ headerName: 'Last name', field: 'lastName' },
{ headerName: 'First name', field: 'firstName' },
{ headerName: 'DOB', field: 'dob', cellRenderer: 'dateTimeRenderer' },
{ headerName: 'Policy start', field: 'policyStartDate', cellRenderer: 'dateTimeRenderer' },
{ headerName: 'Policy end', field: 'policyEndDate', cellRenderer: 'dateTimeRenderer' }
]
frameworkComponents = {
dateTimeRenderer: DateTimeRenderer
}
And I just need to make sure my agGrid knows about this new frameworkComponents section:
<ag-grid-angular
class="ag-theme-material"
[rowData]="rowData"
[columnDefs]="columnDefs"
[frameworkComponents]="frameworkComponents" >
</ag-grid-angular>
And that's it.
Again, the nice thing about this is I can use this date formatter anywhere throughout my code, and all the logic is in one place.
It's just shocking that, in 2020, we actually need to write our own date formatting function for an up-to-date grid like agGrid... this really should've been included in the agGrid libraries.
For Angular, if you want to do this without moment.js you can try something like below:
import { Component, OnInit, Inject, LOCALE_ID } from '#angular/core';
import { formatDate } from '#angular/common';
#Component({
selector: 'app-xyz'
})
export class xyzComponent implements OnInit {
constructor( #Inject(LOCALE_ID) private locale: string ) {
}
columnDefs = [
{headerName: 'Submitted Date', field: 'lastSubmittedDate', cellRenderer: (data) => {
return formatDate(data.value, 'dd MMM yyyy', this.locale);
}];
}
This component is using format date of angular/common
(Working & Optimized solution for date formatting is here!)
Tested on Angular 8 with dynamic data where date is coming like 2019-11-16T04:00:00.000Z.
In Ag-grid if you use valueFormatter, then no need of including "field:'Order Date'".
Also following Ragavan Rajan's answer. So you need to install moment.js in your angular CLI.
Working code and installation is below:
//Install moment.js in angular 8 cli.(no need of --save in latest versions
npm install moment
//In your component.ts
import * as moment from 'moment';
//Inside your colDef of ag-grid
{
headerName: "Effective Date",
field: "effectiveDate",
valueFormatter: function (params){
return moment (params.value).format ('DD MMM, YYYY');
}
/*
* This will display formatted date in ag-grid like 16 Nov, 2019.
* field name's value is from server side.(column name).
*/
If you are using AdapTable then you can do it via their Format Column function which can be applied either at design-time or run-time. And there you can choose pretty much any DateTime format that you want.
https://demo.adaptabletools.com/style/aggridformatcolumndemo
if you have two subfields like "Start Date" and "End Date" then you are supposed to do like this:
{
headerName: "Date Range",
children: [
{
field: 'StartDate',
cellRenderer: (data) => {
return data ? (new Date(data.value)).toLocaleDateString() : '';
}
},
{
field: 'EndDate',
cellRenderer: (data) => {
return data ? (new Date(data.value)).toLocaleDateString() : '';
}
}
],
}
I'm Using Angular 10, And I achieved the date formatting by using cellRenderer and DatePipe
{
field: "fieldName",
cellRenderer: (res) => {
const datepipe : DatePipe = new DatePipe("en-US");
var x = datepipe.transform(res.data.fieldName.split('T')[0],"yyyy-MM-dd");
return x;
}
},
Split('T') is used because when you call the Api, date comes in this format
"2021-07-31T00:00:00.000Z".
Try this:
{
headerName: 'Order Date',
field: 'OrderDate',
valueFormatter: function (params) {
var nowDate = new Date(parseInt(params.value.substr(6)));
return nowDate.format("yyyy-mm-dd");
}