I have a DatePicker in UI5 application. My server is in Australia. When I create any record in IST time, it is working fine. But when a user tries to create any record in Australia, the date value is incremented by 1. That is "31" coming as "32". Do I need to consider the time zone?
UI5 already takes care of handling dates properly if you use the binding type sap.ui.model.odata.type.DateTime in the value binding definition of your DatePicker.
Display the date in UTC by adding UTC: true to the formatOptions (Optional).
Store the date in UTC by adding displayFormat: 'Date' to the constraints.
In sap.ui.model.odata.v2.ODataModel, this type (sap.ui.model.odata.type.DateTime) is represented as a Date. With the constraint displayFormat: 'Date', the time zone is UTC and the time part is ignored.
(...) In this case, only the date part is used, the time part is always 00:00:00, and the time zone is UTC to avoid time-zone-related problems.
Here is a live demo:
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/model/odata/v2/ODataModel",
"sap/ui/core/mvc/XMLView",
], function(ODataModel, XMLView) {
"use strict";
const model = new ODataModel({
serviceUrl: [
"https://cors-anywhere.herokuapp.com/", // proxy
"https://services.odata.org/V2/(S(SO46024229))/OData/OData.svc",
].join(""),
defaultBindingMode: "TwoWay",
preliminaryContext: true,
tokenHandling: false, // service does not provide CSRF tokens
});
Promise.all([
sap.ui.getCore().loadLibrary("sap.m", true),
sap.ui.getCore().loadLibrary("sap.ui.unified", true),
]).then(() => XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc" height="100%">
<DatePicker id="dp" xmlns="sap.m" width="auto" placeholder="Date"
binding="{
path: '/Products(0)',
parameters: {
select: 'ID,ReleaseDate'
}
}"
value="{
path: 'ReleaseDate',
type: 'sap.ui.model.odata.type.DateTime',
constraints: {
displayFormat: 'Date',
nullable: false
}
}"
/>
</mvc:View>`,
models: model,
afterInit: function() {
const fn = e => e.getSource().getBindingContext().getModel().submitChanges();
this.byId("dp").attachChange(fn);
},
}).then(view => {
const messageManager = sap.ui.getCore().getMessageManager();
messageManager.registerObject(view.placeAt("content"), true);
}));
}));
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-async="true"
data-sap-ui-compatversion="edge"
data-sap-ui-modules="sap/ui/thirdparty/datajs"
data-sap-ui-xx-waitfortheme="rendering"
></script><body id="content" class="sapUiBody sapUiSizeCompact"></body>
The internal module datajs parses the incoming Emd.DateTime string in native JS date object, and the module sap.ui.model.odata.type.DateTime stores it in the model as long as the constraints aren't violated.
Reference
Documentation topic: Date and Time Related Controls: Data Binding
API reference: sap.ui.model.odata.type.DateTime
prepareDatesToDisplay: function(oDate){ //to display dates from backend
var oTempDate = new Date(oDate);
oDate = new Date(oTempDate.getTime() + oTempDate.getTimezoneOffset() * (60000));
return oDate;
},
changeDateToUTC: function(oDate){ //for sending dates to backend
var oTempDate = new Date(oDate.setHours("00","00","00","00"));
oDate = new Date(oTempDate.getTime() + oTempDate.getTimezoneOffset() * (-60000));
return oDate;
},
Related
I wanto to disabled all the dates after a date that a person choose, so I call a function who is doing
$( "#final_date" ).datepicker({ datesDisabled: ['+m'] });
And my datepicker is like that
activeDate() {
$("#initial_date").datepicker({
changeMonth: true,
changeYear: true,
format: 'dd/mm/yyyy',
startView: "days",
minViewMode: "days",
language: 'pt-BR'
});
$("#final_date").datepicker({
changeMonth: true,
changeYear: true,
format: 'dd/mm/yyyy',
startView: "days",
minViewMode: "days",
language: 'pt-BR',
datesDisabled: this.disabledDates
});
}
But only one day after my date is being disabled, what am I doing wrong?????
Given that the goal is to
disable all dates after a date
The bootstrap datepicker documentation says you can do this with maxDate.
Takes a maxDate string, Date, moment, boolean:false parameter and disallows the user to select a moment that is after that moment. If a boolean:false value is passed options.maxDate is cleared and there is no restriction to the maximum moment the user can select. [emphasis mine]
Try this (while passing in your value for final_date):
final_date = '2019-11-11';
$( "#final_date" ).datepicker({ maxDate: final_date });
I have an "Add New…" screen with multiple sap.m.Input fields. Everything is working. I submit the form and the values are stored in the DB. But once I re-open this "Add New…" screen, I get the form with previously entered values.
Currently, I can solve the issue iterating over all sap.m.Input fields with sap.ui.core.Element, resetting the values:
Element.registry.forEach(el => {
if (el.isA("sap.m.Input") && el.sId.includes(inputFieldsMask)) {
sap.ui.getCore().byId(el.sId).setValue("");
}
});
Where inputFieldsMask is a mask for all input fields of the relevant screen.
As far as I understand, Element.registry.forEach iterates over all controls in the app, therefore I'm not sure that, from a performance point of view, it's an optimal approach to clean up the fields.
Is there a better way to reset input fields from the previously entered values?
There are several ways to reset the control values depending on what kind of approach you took to create the new entry. Generally, we can make use of the following APIs:
Pass the context to the target container.
In case of working with client-side models: targetContainer.bindElement("newItemPath").
Otherwise, call myV2ODataModel.createEntry("/ThatSet", {...}), which returns a new context, and then pass it to targetContainer.setBindingContext(context, "modelName").
This resolves all the relative bindings in the target container.
<user enters some values and submits ...>
targetContainer.unbindElement("modelName") after the edit was successfully stored.
By unbinding element, relatively bound control values are reset automatically.
Example (using client-side model):
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/mvc/XMLView",
"sap/ui/model/json/JSONModel",
"sap/base/util/uid",
], (XMLView, JSONModel, createPseudoUniqueID) => XMLView.create({
definition: `<mvc:View xmlns:mvc="sap.ui.core.mvc" height="100%">
<App xmlns="sap.m">
<Page backgroundDesign="List" title="Resetting inputs via client-side Model and Context">
<headerContent>
<Button id="addBtn" text="Add Item" type="Emphasized" />
</headerContent>
<List id="myList" growing="true" items="{
path: '/myItems',
key: 'key',
templateShareable: false
}">
<StandardListItem title="{value}" info="Key: {key}"/>
</List>
</Page>
<dependents>
<Dialog id="myDialog"
icon="sap-icon://ui-notifications"
title="New Item"
draggable="true"
class="sapUiResponsiveContentPadding"
>
<Input id="myInput"
placeholder="<New value>"
valueLiveUpdate="true"
value="{
path: 'value',
type: 'sap.ui.model.type.String',
constraints: {
minLength: 1
}
}"
/>
<beginButton>
<Button
text="Submit"
enabled="{= !!%{value} && !%{messages>/}.length}"
/>
</beginButton>
</Dialog>
</dependents>
</App>
</mvc:View>`,
models: {
undefined: new JSONModel({
"myItems": [],
}),
"messages": sap.ui.getCore().getMessageManager().getMessageModel()
},
afterInit: function() {
sap.ui.getCore().getMessageManager().registerObject(this, true);
this.byId("addBtn").attachPress(handleAddPress.bind(this));
this.byId("myInput").attachSubmit(handleSubmit.bind(this));
this.byId("myDialog").setEscapeHandler(onESCPress.bind(this))
.attachAfterClose(onAfterClose.bind(this))
.getBeginButton().attachPress(handleSubmit.bind(this));
function handleAddPress(event) {
const dialog = this.byId("myDialog");
const listBinding = this.byId("myList").getBinding("items");
listBinding.suspend(); // Do not update the list yet
this._currentItems = this.getModel().getProperty("/myItems"); // temp in case user cancels
dialog.getModel().setProperty("/myItems", this._currentItems.concat({})); // new empty item
dialog.bindElement("/myItems/" + listBinding.getLength()); // enable data synchronization via TwoWay binding
dialog.open();
}
function onESCPress(promise) {
const model = this.getModel();
model.setProperty("/myItems", this._currentItems, /*context*/null, /*async*/true);
return promise.resolve(); // continue closing dialog
}
function onAfterClose(event) {
handleAfterClose(event.getSource(), this.byId("myList").getBinding("items"));
}
function handleAfterClose(dialog, listBinding) {
dialog.unbindElement(); // reset data
dialog.setBusy(false);
listBinding.resume();
}
function handleSubmit() {
const dialog = this.byId("myDialog");
if (!dialog.getBeginButton().getEnabled()) return; // something is wrong
dialog.setBusy(true);
if (!this._isStillRequesting) {
this._isStillRequesting = true;
/* send request */setTimeout(mySuccessHandler.bind(this), 3000)
};
}
function mySuccessHandler(newKeyFromServer = createPseudoUniqueID()) {
const dialog = this.byId("myDialog");
this._isStillRequesting = false;
if (!dialog.isOpen()/* request was aborted e.g. by pressing ESC */) {
return; // exit early
}
const context = dialog.getBindingContext();
const value = context.getProperty("value");
dialog.getModel().setProperty(context.getPath("key"), newKeyFromServer);
dialog.close();
sap.ui.require([
"sap/m/MessageToast"
], MT => window.requestAnimationFrame(() => MT.show(`${value} created`)));
}
},
}).then(view => view.placeAt("content"))));
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core,sap.m"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-async="true"
data-sap-ui-compatversion="edge"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-xx-waitForTheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
As explained above, binding and unbinding element also applies to server-side models such as v2.ODataModel.
Benefits
✅ Reduced overload: no need to iterate over all existing controls. Reset only those automatically that need to be reset.
✅ Control agnostic: does not rely on control specific APIs such as myInput.setValue, mySwitch.setState, etc..
✅ Reduced maintenance costs: no need to maintain list of model properties in controller that application needs to reset manually.
Best practice is to use a model to store your application data and to bind any input field to that model. I added an example here. For the sake of simplicity the model data is cleared when the button is pressed.
In a real world application you would place any setup of the model to the onRouteMatched handler to ensure that the data is in an initial state.
onRouteMatched : function(event) {
this.getView().getModel().setData({
"firstName": "",
"lastName": ""
});
}
Bind all your control values to a model. Then reset this model after you've successfully saved the data.
Example:
control1.bindProperty("value", "/controlValues/control1Value"); // Binding
// control1.bindProperty("value", "/controlValues/name");
// <Input value="{/controlValues/name}" /> // <-- ideal binding in xml view
this.getView().getModel().setProperty("/controlValues", this.resetFormData()); // Clear Model
resetFormData: function () {
var emptyControlValues = {
"control1Value": "", // "name": "", <-- bind to control
"control2Value": 0, // "age": 0,
"control3Value": "", // "address": "",
"control4Value": "" // "tel": ""
};
return emptyControlValues;
};
I am using the ionic 4 ion-datetime picker to try to select a date in a form, though when a new date is selected, it does not update the variable.
I've tried using all of the different combinations I know, but I've included all of them here in this example.
<form [formGroup]="upsert" (ngSubmit)="submitUpsert()">
<ion-datetime
display-format="MM DD, YYYY"
picker-format="MM DD YYYY"
min="2010"
max="2030"
class="form__group__item--input has-value"
formControlName="date"
placeholder="Select Date"
[value]=date
[(ngModel)]="event.today"
(ngModelChange)="event.today"
></ion-datetime>
</form>
and in my form controller I have:
constructor(
private db: DatabaseService,
private modalController: ModalController,
private formBuilder: FormBuilder
) {
this.upsert = this.formBuilder.group({
title: ['', Validators.compose([Validators.required])],
date: ['', Validators.compose([Validators.required])],
notes: [''],
location: [''],
timezone: [''],
});
this.event.today = moment().toISOString(true);
this.event.timezone = moment().format('ZZ');
}
And eventually, I use the form submit action
submitUpsert() {
console.log("new date", this.event.today);
if(this.upsert.invalid) {
const error = {
code: "001",
message: this.upsert.status
};
this.showError(error);
} else {
this.db.upsert(this.upsert.value).then(eid => {
console.log("Success", eid);
this.hideUpsert();
}, error => {
this.showError(error);
console.error(error);
});
}
}
In the latest beta API, it does not mention to use [(ngModel)] or (ngModelChange), but it was the only way I could get a default date (of today) pre-selected.
Unfortunately, it's not updating the model nor the form object. Any thoughts?
You are using both ngModel and FormControlName. Use either one. you can update the form control value using setValue() method.
this.event.today = moment().toISOString(true);
this.upsert.get('date').setValue(this.event.today);
Try bind the model like this <ion-datetime [(ngModel)]="newsItem.validTo" name="validTo"></ion-datetime> The name attribute is required if the ion-datetime is within an ngForm.
This worked for me in Ionic 4.
I'm trying to create a datepicker with Materialize.
According to the documentation the datepicker should close when the user selects a date.
That's not working in my page. I'm using the latest Chrome browser on Windows. I've tried IE browser, but there's the whole datepicker not showing...
Click here for my page (input 3 and 4 are datepickers)
My javascript:
$('#due_date').pickadate({
monthsFull: [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december' ],
monthsShort: [ 'jan', 'feb', 'maa', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec' ],
weekdaysFull: [ 'zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag' ],
weekdaysShort: [ 'zo', 'ma', 'di', 'wo', 'do', 'vr', 'za' ],
today: 'vandaag',
clear: 'verwijderen',
close: 'sluiten',
firstDay: 1,
format: 'dd-mm-yyyy',
formatSubmit: 'yyyy/mm/dd',
closeOnSelect: true,
selectMonths: true, // Creates a dropdown to control month
selectYears: 3, // Creates a dropdown of 15 years to control year
min: new Date()
});
Can anyone help me to fix these datepickers?
Please add below few lines to your code..
onSet: function (ele) {
if(ele.select){
this.close();
}
}
var datePicker = $('.datepicker').pickadate({
onSet: function () {
this.close();
}
});
The developer of materialize thought that it would match Google's date picker if it doesn't close on select according to this issue:
https://github.com/Dogfalo/materialize/issues/870
However you can change the source code of materialize if you don't mind, like this:
https://github.com/Dogfalo/materialize/commit/db0629d30a9d3e5ac06a019955a8e10062f91833
Better Solution: Use if ( 'select' in arg ) condition so that the datepicker dialog wont hide when you select month or year.
$('.datepicker').pickadate({
onSet: function( arg ){
if ( 'select' in arg ){ //prevent closing on selecting month/year
this.close();
}
}
});
i had the same problem and i solved it this way:
$('.datepicker1').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15, // Creates a dropdown of 15 years to control year
min: true,
onOpen: function () {
this.clear();
},
onSet: function () {
var x,y,year,date,month;
x = $('.datepicker1').pickadate().val().toString();
y = x.split(/[ ,]+/);
date = y[0];
month = y[1];
year = y[2];
console.log(y[0]+" "+ y[1]+ " "+ y[2]);
if(date && month && year){
this.close();
}
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Materialize Datepicker</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/css/materialize.min.css">
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/js/materialize.min.js"></script>
</head>
<body>
<form class="col s6">
<label for="To" >To : </label>
<input type="date" id="To" class="datepicker1">
</form>
<script src="site.js"></script>
</body>
</html>
The onSet: function(called when a date is set) ensures the date,month and year are entered and closes only if the date is set.
The onOpen: function(called when the datepicker opens) clears the input when datepicker is opened again, useful in case when the user inputs the wrong date.. Without using this function , the datepicker cant navigate though different months,years without closing..
Hope this solves your problem.
If "closeOnSelect: true" is not working then you can call click event of the close button
HTML code for input element:
<input type='text' id='purchase_date'/>
Js code for the element:
jQuery(document).ready(function(){
$('#purchase_date').pickadate({format: 'yyyy-mm-dd'})
.on('change', function(){
$(this).next().find('.picker__close').click();
});
});
Hope this will solve your problem.
Tested on materializecss 1.0.0: use onSelect callback
$('.datepicker').datepicker({
autoClose: true,
today: 'Today',
clear: 'Clear',
close: 'Close',
format: 'dd/mm/yyyy',
//perform click event on done button
onSelect: function () {
$('.confirmation-btns .datepicker-done').click();
}
});
I have a couple of columns in jqGrid with edittype="select". How can I read the option value of the value currently selected in a particular row?
e.g.: When I provide the following option, how do I get "FE" for FedEx, etc.
editoption: { value: “FE:FedEx; IN:InTime; TN:TNT” }
getRowData() for the rowId/cellname returns only the text/displayed component of the select.
If I set a "change" data event on the column, the underlying fires change events only on mouse clicks, and not keyboard selects (there's numerous references to generic selects and mouse/keyboard issues).
Bottomline, when a new value is selected, I need to know the option value at the time of the change, and also prior to posting to the server.
You have to set the formatter of the column to 'select'
Example from the wiki:
colModel : [ {name:'myname',
edittype:'select', formatter:'select',
editoptions:{value:"1:One;2:Two"}} ...
]
See more here jqgridwiki
I was having the same problem and this worked like a charm
I just solved this question by using setting JqGrid unformat option and use the following function for unformatting cell value.
function Unformat_Select(cellvalue, options, cellobject)
{
var unformatValue = '';
$.each(options.colModel.editoptions.value, function (k, value)
{
if (cellvalue == value)
{
unformatValue = k;
}
});
return unformatValue;
}
The above method will be called everytime when grid need cell data like when you call "getRowData" method. However, my function only support key-paired value edit option. You need to change your data like the following pattern.
editoption:
{
value:
{
FE:'FedEx',
IN:'InTime',
TN:'TNT'
}
}
For more information about unformat option, you can see at the following link.
JqGrid Wiki - Custom Formatter
PS. It's possible to modify my function to support client-side dropdownlist value. But I think it's impossible to apply this function for server-side dropdownlist value.
Update
In the latest jqGrid 3.8.1, I just found some bug when user cancel editing row(or programmatically call "restoreRow" method), jqGrid will create label by using key of data (instead of value of data). I create the following function to fix this issue. For use this, you must it as custom formatter function of this column. This function maps cell value to value of list by comparing key or value.
function JqGridInlineEditor_SelectFormatter(cellvalue, options, rowObject)
{
var temp = '';
$.each(options.colModel.editoptions.value, function (key, value)
{
if (cellvalue == key || cellvalue == value)
{
temp = value;
return false;
}
});
return temp;
}
So, you can send key or value as column data to be rendered by the above custom formatter.
If in case you have requirement where each row has dropdown and it has values like
FE:'FedEx',
IN:'InTime',
TN:'TNT'
Now instead of saving the data to backend on dropdown change event;you want to save data on "Save" button click at row level but want to save dropdwon selected value (TN) not display text(TNT). You can create another hidden field to set selected country code on inline editing of dropdown. Here when user exit after cell inline editing afterSaveCell method will be called and you can set it as mentioned in below code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>http://stackoverflow.com/q/9655426/315935</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/redmond/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/css/ui.jqgrid.css" />
<style type="text/css">
html, body { font-size: 75%; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/js/i18n/grid.locale-en.js"></script>
<script type="text/javascript">
$.jgrid.no_legacy_api = true;
$.jgrid.useJSON = true;
</script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.3.1/js/jquery.jqGrid.src.js"></script>
<script type="text/javascript">
//<![CDATA[
/*global $ */
/*jslint devel: true, browser: true, plusplus: true, nomen: true, unparam: true */
$(document).ready(function () {
'use strict';
var listOptions = "CN:Canada; US:United States; FR:France; IN:India";
var mydata = [{
name: "Toronto",
country: "CN",
continent: "North America",
countrycode: "CN"
}, {
name: "New York City",
country: "US",
continent: "North America",
countrycode: "US"
}, {
name: "Silicon Valley",
country: "US",
continent: "North America",
countrycode: "US"
}, {
name: "Paris",
country: "FR",
continent: "Europe",
countrycode: "FR"
}, {
name: "Pune",
country: "IN",
continent: "Asia",
countrycode: "IN"
}]
$("#gvManageMapping").jqGrid({
data: mydata,
datatype: "local",
colNames: ["Name", "Country", "Continent", "countrycode"],
colModel: [{
name: 'name',
index: 'name',
editable: false,
},
{
name: 'country',
index: 'country',
editable: true, edittype: "select", formatter: 'select', editoptions: {
value: listOptions,
}, editrules: { required: true, integer: false }, formatter: "select"
},
{
name: 'continent',
index: 'continent',
editable: false,
},
{
name: 'countrycode',
index: 'countrycode',
editable: false
}],
afterSaveCell: function (rowid, cellname, value) {
var selectedCountryCode, $this;
if (cellname === 'country') {
$this = $(this);
selectedCountryCode = $this.jqGrid("getCell", rowid, 'country');
$this.jqGrid("setCell", rowid, 'countrycode', selectedCountryCode);
}
},
pager: '#pager',
'cellEdit': true,
'cellsubmit': 'clientArray',
editurl: 'clientArray'
});
});
//]]>
</script>
</head>
<body>
<table id="gvManageMapping"><tr><td /></tr></table>
<div id="pager"></div>
</body>
</html>
The documentation for getRowData states:
Do not use this method when you editing the row or cell. This will return the cell content and not the actuall value of the input element
Is the row still being edited when you call getRowData()?
Update
Agreed, jqGrid does not handle <select> very well. In my application I actually was able to get around this by not specifying an edit option (meaning, key/value were both "FedEx"); the translation to ID is then done on the server. This is not the right way to code this, but it worked well enough for my needs at the time.