top of page
Search
  • Writer's picturegirizano

Date picker in another language

Updated: Feb 17, 2020

February 2020: the Wix DatePicker has been translated so this solution is obsolete.

A working demo version is available from the menu.

Abstract

This article describes how to use an alternative date picker in another (natural) language in Wix Code. It is based on flatpickr (https://flatpickr.js.org) and the Wix html-component.


The problem

The Wix date picker only supports English. Also, it does not allow time picking. So I started to look for a solution as long as Wix does not offer a translation and a time picker. This is the result.


A work in progress

This thing can be improved and enhanced in many ways. Feel free to do so. If you have something better, email your improvements (both Wix Code and html-source from the component), but make sure that, unless impossible, they are replacements to my code, so I can just replace. I am NOT going to edit your code snippets into my version.

Any questions should be kept on the Wix Forum, so others can learn: it is the most natural place to do so.


The idea behind it

I wanted a date picker that looked like the Wix Date Picker and handled the data type Date, not a date as a string (for obvious reasons). Problem is, that if you define a date field in your collection and you want to tie this to an input field on a form using a Dataset, Wix only allows you to select their Date Picker. And that was the one I did NOT want to use.

So I did this: I use the Wix Date Picker, bind it to a date field in the dataset, set hiddenOnLoad to true and display the date in a separate text field. The calendar icon I copied and uploaded it as an image, which I put next to the text field. Around these three elements I draw a box (so all keeps nicely together on mobile).


When a date is filled from the database (update mode), a function copies the date from the Wix Date Picker into the text field. When a date is selected from the new date picker, the date is fed to the Wix Date Picker and the same function displays it in the text field.

Note that it´s a text field, so no manual input is possible (but you could develop it).


A .save() will now always save the date from the Wix Date Pickr to the collection, simply because it is bound to a field in the collection.


We use onMessage/postMessage to communicate between the Wix side and the html-component. It uses a 'heart beat' technique to make sure it runs in Publish Mode as described in this article.

EDIT: the heart beat works in the situation where page is loaded first and then the html-component is loaded (it sends a message back to $w). But, when the component is loaded BEFORE the Wix page (and this started to happen), the Wix Page does not listen yet and it goes wrong. That´s why we do a "double whammy": on $w.onReady we send the message (which will be picked up if the component loaded before the page AND we send it when we receive the heart beat (=conponent loaded after Wix Page).


The example

Make sure you follow this example to the letter. Don´t go horsing around with your own field names and different collections, because if it doesn´t work, I cannot help you. Simply get this example working and use it as a reference for your own implementation.


Step 1: build a Collection

Make a collection called "Events". Set the correct Permissions (like Custom: Anyone, Anyone, Anyone, Admin). In it, we specify 4 fields:

  1. title

  2. fldStartDate (type date)

  3. fldEndDate (same)

  4. fldSelect (string)

Fill only one row with data, but make sure that, for our example, the value fldSelect holds "12345". It should look something like this:



Step 2: add a normal page

Add a page (any name, like "flatpickr") as a normal page (not a Dynamic Page) and add a dataset to it. Call this dataset "dataset1". Connect it to the "Events" collection, set Permissions to Read/Write and add a filter on fldSelect "is 12345".


Step 3: add first Date Pickers parts

Draw the following elements on your page:

  1. an user input element (EventDescr), bound to the 'title'-field of the Events-collection

  2. a Box (box1) with its border size set to 1px, width 315 px

  3. a textbox (txtDate1) with its border size set to 0px. Put at least a "." (dot) in it, or it will disappear if left empty. Put it inside box1 till it snaps.

  4. a Wix Date Picker (datePicker1) right next to txtDate1, set to hidden onLoad and resized to its minimum dimensions. Put it inside box1 till it snaps.

  5. an image (image1) right next to datePicker1. Put it inside box1 till it snaps. Now upload the Wix icon onto it. See below (right-click it, Save, upload to Wix, use it)

  6. a html-component (html1) with the following dimensions; W:315, H:301. Set it to hidden onLoad. Drag it underneath box1. Copy the html source code (see below) into it.

  7. set onClick triggers thru the Property Panel for txtDate1 and image1. Make sure they are called txtDate1_click and image1_click (and not txtDate1:click_1 or whatever)


Date picker icon. Use this icon for image1


Now, your page should look like this (html-component not visible): an input field, a box, and inside the text box, the original Wix Date Picker resized to its minimum and the image.








And with the html-component like this:



Step 4: bind the Wix Date Picker

Click the Wix Date Picker and bind it to field fldStartDate from the Events-collection.


Step 5 : the second Date Picker

Repeat steps 3: 1 - 7 for the second Date Picker. (Tip: select box1, ctrl-c/ctrl-v).

  1. Make sure the elements are called: box2, txtDate2, datePicker2 and image2, that the onClick handlers (Property Panel) are called txtDate2_click and image2_click for txtDate2 and image2 and that the html-component is called html2. Set its height to 343, so it will allow for the time box.

  2. You do NOT have to change the html of html2 (but in our example we did. We changed the Thema and the language [German: de])

  3. Do NOT forget to bind the Wix Date Picker to field fldEndDate and do not forget the onCLicks thru Property Panel!!!!


Now, it should look something like this (html1not visible):



Step 7: bring html1 to front

Find html1, right-click, select "Arrange" and select "Bring to front". This will prevent the calendar from displaying UNDER the second date picker.


Step 8 : add button and animation text

  1. add a button "btnSave", change its text to "Save"

  2. add a text box "txtSaveMessage" and put at least a dot in it. Put the textbox underneath the button. Set it to hiddenOnload.

Step 9: add Wix Code

Delete all code (the onClick placeholders are prob. there) from the page and copy and paste the Wix Code below. If all has been done correctly, you should have no red dots.


Step 10: Publish and try

It runs in both Preview and Publish Mode.



Unbound date picker

If you want a date picker that is NOT bound to a field in a dataset, just kill all the code related to #dataset1. Make sure that in sendDate, you do not send a field name, but a valid date (any date).



Wix Code

$w.onReady(function () { //Make sure your html-component measures W:315xH301 pixels // make sure your dataset is called dataset1 $w("#dataset1").onReady(() => { // if the component loaded before this page, the LoadOK is not received, so send it sendDate("#html1", "fldStartDate"); // use a function to make the date readable and NOT toLocaleString()!!. The latter will make the // page render twice, the first time with a wrong date format (since there IS no Locale setting on the server) // send a date to the second date picker sendDate("#html2", "fldEndDate"); // and your first html-component html1 $w("#html1").onMessage((event, $w) => { let boolEventIsString = (typeof event.data === "string"); if (!boolEventIsString) { // if it´s not a string with LoadOK then it must be a date // make sure your Wix Datepicker is called datePicker1 $w("#datePicker1").value = new Date(event.data); // and your Wix text field is called txtDate1 $w("#txtDate1").text = convertLongDate($w("#datePicker1").value); // hide calendar when date has been selected toggleDatePicker($w, "#html1"); // if it is a string (LoadOK), the component is ready, so send the date to the component } else { sendDate("#html1", "fldStartDate"); } }); // this is exactly the same code as above, but now for html2, with different element-id´s //Make sure your html-component measures W:315xH343 pixels $w("#html2").onMessage((event, $w) => { let boolEventIsString = (typeof event.data === "string"); if (!boolEventIsString) { // if it´s not a string with LoadOK then it must be a date // make sure your Wix Datepicker is called datePicker1 $w("#datePicker2").value = new Date(event.data); // and your Wix text field is called txtDate1 $w("#txtDate2").text = convertLongDate($w("#datePicker2").value); // hide calendar when date has been selected toggleDatePicker($w, "#html2"); // if it is a string (LoadOK), the component is ready, so send the date to the component } else { sendDate("#html2", "fldEndDate"); } }); // setting a date in code does not raise the onChange event (as per documentation). So we have // to find an event that IS triggered when the wix datePicker recieves a value from code. //And that´s the onCustomValidation event. So we (mis)use this. $w("#datePicker1").onCustomValidation((value, reject) => { // set the (visible) text field to the date that was received from the wix DatePicker // We use a separate functiom to format it. Not really necessary, for the flatpickr also return this, // but I had no time to find out how that worked. This was easier, but feel free to experiment $w("#txtDate1").text = convertLongDate(value); // Another problem. Turned out that Wix would not save the data on the form if only dates had been // changed. Above, we already knew that the onChange is not fired when you set a Wix Datepicker value // in code. Because, according to Wix Code, there is no change, there is also nothing to save. // So we use the dataset´s setFieldValue to hard set the date. This, btw, also triggers an onItemValuesChanged (see below) //Don´t forget to set the correct field name here !!!! $w('#dataset1').setFieldValue("fldStartDate", value); }); // below a block copy for date 2 $w("#datePicker2").onCustomValidation((value, reject) => { // set the (visible) text field to the date that was received from the wix DatePicker // We use a separate functiom to format it. Not really necessary, for the flatpickr also return this, // but I had no time to find out how that worked. This was easier, but feel free to experiment $w("#txtDate2").text = convertLongDate(value); // Another problem. Turned out that Wix would not save the data on the form if only dates had been // changed. Above, we already knew that the onChange is not fired when you set a Wix Datepicker value // in code. Because, according to Wix Code, there is no change, there is also nothing to save. // So we use the dataset´s setFieldValue to hard set the date. This, btw, also triggers an onItemValuesChanged (see below) //Don´t forget to set the correct field name here !!!! $w('#dataset1').setFieldValue("fldEndDate", value); }); $w("#dataset1").onBeforeSave(() => { $w("#txtSaveMessage").text = "Saving, please wait."; $w("#txtSaveMessage").show(); // unhide the "Dates saved text after row is saved" }); $w("#dataset1").onAfterSave(() => { $w("#txtSaveMessage").text = "Saved. Now reload the page (F5) to see that it was so."; console.log("In aftersave"); }); $w("#dataset1").onItemValuesChanged((itemBeforeChange, updatedItem) => { console.log("in onItemValuesChanged"); // does nothing, but is raised when user changes some field on form or, in our case, after the // setFieldValue }); }); }); function convertLongDate(DateIn) { // takes a javascript Long Date and returns a date formatted as DD/MM/YYYY. Do NOT use .toLocaleString(). Doing so will // force Wix to render the page twice, 1 time on the server, showing a strangely formatted date (because there is no browser locale // on the server), a flicker and then the correct date let thisDay = DateIn.getDate(); let strthisDay = "0" + thisDay.toString(); strthisDay = strthisDay.substr(strthisDay.length - 2, 2); let thisMonth = DateIn.getMonth() + 101; let strthisMonth = thisMonth.toString(); strthisMonth = strthisMonth.substr(strthisMonth.length - 2, 2); let thisYear = DateIn.getFullYear(); let formattedDate = strthisDay + "/" + strthisMonth + "/" + thisYear; return formattedDate; } export function sendDate(element, fieldname) { // not really necessary to make an array, but for future purposes, it´s better to do so var objMessage = []; let thisdatDate = $w('#dataset1').getCurrentItem()[fieldname]; // push value onto the array objMessage.push(thisdatDate); // and now send this date to the html-component $w(element).postMessage(objMessage); } // guess from here on it needs no explanation export function toggleDatePicker($w, strElementId) { // show/hide the html-component holding the flatpickr let boolDatePickerIsVisible = $w(strElementId).isVisible; if (boolDatePickerIsVisible) { $w(strElementId).hide(); } else { $w(strElementId).show(); } } export function txtDate1_click(event, $w) { toggleDatePicker($w, "#html1"); } export function image1_click(event, $w) { toggleDatePicker($w, "#html1"); } export function txtDate2_click(event, $w) { toggleDatePicker($w, "#html2"); } export function image2_click(event, $w) { toggleDatePicker($w, "#html2"); } export function btnSave_click(event, $w) { console.log("in btnsave"); $w("#dataset1").save(); } HTML for html-component1

<!doctype html>

<html>

<head>

<!-- Documentation for flatpickr at https://flatpickr.js.org. Remember that you do NOT have to change anything in this file, even if you use 2 or 3 datepickers, apart from some settings for theme, language, timepickr etc. But this file will be identical for all instances of the datepickr-->


<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.css">

<!-- Below indicate the style sheet you want to use for colors, etc. See flatpickr web site for options. -->

<!-- I rem-ed out the material_green design. If no theme is specified, flatpickr uses its default colours, grey and blue, what we use in our example -->

<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/themes/material_green.css"> -->


</head>

<script type="text/javascript">

window.onmessage = (event) => {

if (event.data) {

let datDate=event.data[0];

drawDatePicker(datDate);

}

};


function sendLoadMessage () {

window.parent.postMessage("onLoad", "*");

}


</script>

<!-- The font used in the datepickr comes from this body tag. Change Verdana into anything else you´d like -->

<body onload="sendLoadMessage ();" style="font-family: verdana;background-color:white;margin:0;padding:0">

<!-- set a hidden field from which the datepicker is triggered -->

<div>

<input type="text" hidden="true" id="myDate" data-input>

</div>

<!-- jQuery -->

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Flatpickr -->

<script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.js"></script>


<!-- Make sure below you load the correct language file. Here we loaded Spanish. See flatpickr documentation -->


<script src="https://npmcdn.com/flatpickr/dist/l10n/es.js"></script>

<script>


<!-- Below, set other properties, like the timepicker or others. See flatpickr documentation. Make sure to change the locale, like fr, jp, de, nl, etc -->


function drawDatePicker (dateIn) {

$("#myDate").flatpickr({

<!-- enableTime: true, -->

dateFormat: "d/m/Y",

inline: true,

locale: "es",

defaultDate : dateIn,

onChange: function(selectedDates, dateStr, instance) {

window.parent.postMessage(selectedDates, "*");

},

});

}


</script>

</body>

</html>


HTML for html-component2 (compare the 2 and you will see the only difference is the theme, the language and the time picker)

<script type="text/javascript">

window.onmessage = (event) => {

if (event.data) {

let datDate=event.data[0];

drawDatePicker(datDate);

}

};


function sendLoadMessage () {

window.parent.postMessage("onLoad", "*");

}


</script>

<!-- The font used in the datepickr comes from this body tag. Change Verdana into anything else you´d like -->

<body onload="sendLoadMessage ();" style="font-family: verdana;background-color:white;margin:0;padding:0">

<!-- set a hidden field from which the datepicker is triggered -->

<div>

<input type="text" hidden="true" id="myDate" data-input>

</div>

<!-- jQuery -->

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<!-- Flatpickr -->

<script src="https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.2.3/flatpickr.js"></script>


<!-- Make sure below you load the correct language file. Here we loaded Spanish. See flatpickr documentation -->


<script src="https://npmcdn.com/flatpickr/dist/l10n/de.js"></script>

<script>


<!-- Below, set other properties, like the timepicker or others. See flatpickr documentation. Make sure to change the locale, like fr, jp, de, nl, etc -->


function drawDatePicker (dateIn) {

$("#myDate").flatpickr({

enableTime: true,

dateFormat: "d/m/Y",

inline: true,

locale: "de",

defaultDate : dateIn,

onChange: function(selectedDates, dateStr, instance) {

window.parent.postMessage(selectedDates, "*");

},

});

}


</script>

</body>

</html>

800 views0 comments

Recent Posts

See All

Commercial (psychological) rounding

Abstract In this contribution, we publish an algorithm for commercial (psychological) rounding. So what is that? The problem: two ways of rounding Rounding is a poorly understood art. As far as I can

bottom of page