Improve js performance

Questions and discussion about using ProcessMaker: user interface, running cases & functionality

Moderator: amosbatto

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Improve js performance

Unread postby cosyxu » Tue Nov 07, 2017 8:31 pm

Good morning,

I was wondering is there any way to improve the performance of JS code in Dyanform when I had more than 200 rows in my grid?

I am using web-entry form, when I click my "search button", it runs an ajax function to manipulate data from DB to the Grid, when the number of rows excess 200, it become very slow to show the full grid.

Any ideas?

Thanks,
Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Tue Nov 07, 2017 10:22 pm

Short answer: No. The JS code in DynaForms is already minimized, so I don't think you can do much more to speed it up.

You can modify your AJAX to only return only 50 rows at a time and display buttons to show the second, third, fourth, etc. pages of the results.
Get the number of pages: SELECT COUNT(*) FROM X
Then display the buttons:
Page 1: SELECT * FROM X LIMIT 50
Page 2: SELECT * FROM X LIMIT 51, 100
Page 3: SELECT * FROM X LIMIT 101, 150
Page 4: SELECT * FROM X LIMIT 151, 200
etc.

Each time the user clicks on a button, do the query of your database. Use JavaScript to clear all the rows in the grid with grid.deleteRow() and then use grid.addRow() to add each row returned by AJAX to the grid.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Wed Nov 08, 2017 1:05 am

Hi Amosbatto,

Thank you for your reply.

I was wondering is there any way to restructure the following code?

Code: Select all

myJSON = JSON.parse(xmlhttp.responseText);
for (var i = 0; i < oLength; i++) { 
newRow = [
          {"value": myJSON[i].category},
          {"value": myJSON[i].item},
          {"value": myJSON[i].price},
          {"value": 0}
       ];
$("#grid_order").addRow(newRow
});


When I use the above code, it takes 47s to update a grid with 200 rows; and it takes 4s to update a grid with 37 rows.

Therefore, is there any way to change the code and improve the speed of performance?

Many thanks,
Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Wed Nov 08, 2017 10:59 pm

I don't know how to speed up grid.addRow(). You should file a bug report asking for a function to set all the rows in a grid at once.

If this were not a web entry, you could use REST to set the case variable associated with the grid and then call location.reload(). Unfortunately, you are using web entry, so the case doesn't yet exist and you can't set the grid's case variable.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Wed Nov 08, 2017 11:22 pm

If you want to check the code for grid.addRow(), you can find it at line 6786 in workflow/public_html/lib/pmdynaform/build/js/PMDynaform.js

If you only want to read the contents of your grid and not edit it, then I recommend using DataTables in a Panel which is much faster:
http://wiki.processmaker.com/3.0/Panel_Control#Rendering_DataTables_in_the_DynaForm

If you want editing of the table, then see:
https://editor.datatables.net/
You will need to add JS code to your form that is executed by form.setOnSubmit(). Your code can convert the contents of the DataTable to a JSON string and save it in a hidden field. Then a later trigger in your process can call json_decode(@@myHidden) and save it as a normal grid.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Mon Nov 13, 2017 6:13 pm

Hi amosbatto,

Thank you for your reply and the resource.

I still prefer to use grid because I also need the calculation function of the grid. And I have found out it is the form.setOnChange() that slow down the grid.

Therefore, if I don't use JavaScript to calculate the grid(I know it is advised to use js), I can use processmaker built-in function(sum), however I was wondering is there any way that I can change the content of sum area? For example: Your Total is : XXX.

[img]
2017-11-14_9-02-19.png
[/img]
Please see attached screen shot.

Many thanks,
Yuan
Attachments
2017-11-14_9-02-19.png
2017-11-14_9-02-19.png (60.38 KiB) Viewed 131 times

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Mon Nov 13, 2017 9:22 pm

You can set the value of a summed column with this code:
$("#sum-GRID_ID-FIELD_ID").val("X")
Example:
$("#sum-accountsGrid-price").val("353.50")

But it will be overwritten each time a value in the column is changed. You can hide the field and create another field that you will set with JavaScript. For example:

Code: Select all

$("#sum-accountsGrid-price").hide();
$("#sum-accountsGrid-price").parent().append(
'<input id="sum-accountsGrid-price2" style="width: 50%;" readonly="readonly" data-original-title="" title="">');
$("#sum-accountsGrid-price2").val("353.60");
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Mon Nov 13, 2017 11:10 pm

Hi Amosbatto,


Thank you for your solution.

Could I also ask how to add a "loading" image before the grid has been fully display?

Just like when you submit a web-form, there is a "loading image" displaying until the form has been submitted.

2017-11-14_14-10-37.png
2017-11-14_14-10-37.png (4.62 KiB) Viewed 118 times

Thanks in advance,
Yuan

User avatar
programerboy
Posts: 59
Joined: Mon Aug 28, 2017 4:22 am
Country: Iran
Location: Iran, Mashhad

Re: Improve js performance

Unread postby programerboy » Tue Nov 14, 2017 3:14 am

Hi Amosbatto,

Thanks for your answers. But I think Processmaker must add a solution for create paging in grids with ajax, In addition to the method with JavaScript that exist now, Because it crash when the number of records increases and designer must use panel and external libraries and etc.

Thanks

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Tue Nov 14, 2017 8:11 pm

cosyxu wrote:Could I also ask how to add a "loading" image before the grid has been fully display?

Just like when you submit a web-form, there is a "loading image" displaying until the form has been submitted.

2017-11-14_14-10-37.png


Yuan,
To display the loading spinning circles in your DynaForm, you can use this code:
$("body").append("<div class='pmDynaformLoading'></div>");

And to remove them, you can use this code:
$("body").find("div.pmDynaformLoading").remove();
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Tue Nov 14, 2017 8:14 pm

programerboy wrote:Hi Amosbatto,

Thanks for your answers. But I think Processmaker must add a solution for create paging in grids with ajax, In addition to the method with JavaScript that exist now, Because it crash when the number of records increases and designer must use panel and external libraries and etc.

Thanks

Programerboy, please file a bug report requesting this new feature at http://bugs.processmaker.com, and post a link to your bug report here.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Tue Nov 14, 2017 10:54 pm

Hi Amosbatto,


Thank you very much for your solution.

In addition to that, it seems Dynaform use "bootstrap 3 datetimepicker" from
http://eonasdan.github.io/bootstrap-datetimepicker/#no-icon-input-field-only.

If I'd like to use other pattern or style of the datetimepicker control, where and how should I do?

For example, if I want to use " No Icon (input field only)" style, how should I change the existing datetime control to this style?


Thanks,
Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Wed Nov 15, 2017 12:20 am

If you want to get rid of the calendar icon, then you can do this:
$("#DATETIME-ID").find("span.input-group-addon").hide()
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Wed Nov 15, 2017 12:51 am

amosbatto wrote:If you want to get rid of the calendar icon, then you can do this:
$("#DATETIME-ID").find("span.input-group-addon").hide()



If I hide the span, then I can't select the date when I click it.

I have also trid this code, it works, but when I click the text field to select a date, it still show the "required field" error because the value didn't pass into the hiden field for datetime control.

Code: Select all

$("#functionDate").find("input").datetimepicker();


Any ideas? Thanks.
2017-11-15_15-52-18.png
2017-11-15_15-52-18.png (6.95 KiB) Viewed 93 times
2017-11-15_15-53-11.png
2017-11-15_15-53-11.png (39.54 KiB) Viewed 93 times

Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Wed Nov 15, 2017 8:27 pm

Yuan,
You can use this JS code:

Code: Select all

$("#dueDate").find("span.input-group-addon").hide();
$("#dueDate").find("input").datetimepicker();

$("#form\\[dueDate\\]").blur(function() {
  var dt = moment(this.value).format('YYYY-MM-DD HH:mm:ss');
  $("#form\\[dueDate_label\\]").val(dt);
});

Where "dueDate" is the ID of the datetime field.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Wed Nov 15, 2017 9:18 pm

hi Amosbatto,

Thank you for your code.

I have tried and it pass to the value to the <input> but it still show "required error".

Could I also ask how to implement the linked pickers? Please see attached code:

Code: Select all

       $('#startDate').datetimepicker();
         $('#endDate').datetimepicker({
            useCurrent: false
        });
        $("#startDate").on("dp.change", function (e) {
            $('#endDate').data("DateTimePicker").minDate(e.date);
        });
        $("#endDate").on("dp.change", function (e) {
            $('#startDate').data("DateTimePicker").maxDate(e.date);
        });


Any ideas?
Reference:https://eonasdan.github.io/bootstrap-datetimepicker/#linked-pickers
2017-11-16_12-13-36.png
2017-11-16_12-13-36.png (11.6 KiB) Viewed 74 times

Thanks,
Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Thu Nov 16, 2017 9:27 pm

cosyxu wrote:I have tried and it pass to the value to the <input> but it still show "required error".

Don't make it "required" and add code to the form.setOnSubmit() event handler to check whether it is empty.

cosyxu wrote:Could I also ask how to implement the linked pickers? Please see attached code:

Code: Select all

       $('#startDate').datetimepicker();
         $('#endDate').datetimepicker({
            useCurrent: false
        });
        $("#startDate").on("dp.change", function (e) {
            $('#endDate').data("DateTimePicker").minDate(e.date);
        });
        $("#endDate").on("dp.change", function (e) {
            $('#startDate').data("DateTimePicker").maxDate(e.date);
        });


Any ideas?


I can't figure out how to change the properties of existing datetime fields. The workaround is to hide two existing date fields and then place to new date fields in a Panel to replace them. Here is the Panel's HTML code:

Code: Select all

    <div class='col-md-5'>
        <div class="form-group">
            <b>Start Date: </b>
            <div class='input-group date' id='startDate2'>
              <input type='text' class="form-control" />
              <span class="input-group-addon">
                    <span class="glyphicon glyphicon-calendar"></span>
              </span>
            </div>
        </div>
    </div>
    <div class='col-md-5'>
        <div class="form-group">
            <b>End Date: </b>
            <div class='input-group date' id='endDate2'>
              <input type='text' class="form-control" />
              <span class="input-group-addon">
                    <span class="glyphicon glyphicon-calendar"></span>
              </span>
            </div>
        </div>
    </div>


Then, call datetimepicker() on those two new fields in the JS code:

Code: Select all

$('#startDate').hide();
$('#endDate').hide();
$('#datesPanel').css('overflow', 'visible');
$("div.pmdynaform-container").css("overflow", "visible");
$("form.pmdynaform-form").css("overflow", "visible");

$('#startDate2').datetimepicker({
  format: "YYYY-MM-DD"
});

$('#endDate2').datetimepicker({
  useCurrent: false,
  format: "YYYY-MM-DD"
});

$("#startDate2").on("dp.change", function (e) {
  var newDate = moment(e.date).format("YYYY-MM-DD HH:mm:ss");
  $("#endDate2").data("DateTimePicker").minDate(newDate);
  $("#startDate").setValue(newDate);
});

$("#endDate2").on("dp.change", function (e) {
  var newDate = moment(e.date).format("YYYY-MM-DD HH:mm:ss");
  $('#startDate2').data("DateTimePicker").maxDate(newDate);
  $("#endDate").setValue(newDate);
});


LinkedDateTimeFields.png
LinkedDateTimeFields.png (91.32 KiB) Viewed 53 times


See the attached process that shows how to implement it:
linked_date_fields-1.pmx
(27.25 KiB) Downloaded 1 time
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Fri Nov 17, 2017 1:50 am

amosbatto wrote:
cosyxu wrote:I have tried and it pass to the value to the <input> but it still show "required error".

Don't make it "required" and add code to the form.setOnSubmit() event handler to check whether it is empty.

cosyxu wrote:Could I also ask how to implement the linked pickers? Please see attached code:

Code: Select all

       $('#startDate').datetimepicker();
         $('#endDate').datetimepicker({
            useCurrent: false
        });
        $("#startDate").on("dp.change", function (e) {
            $('#endDate').data("DateTimePicker").minDate(e.date);
        });
        $("#endDate").on("dp.change", function (e) {
            $('#startDate').data("DateTimePicker").maxDate(e.date);
        });


Any ideas?


I can't figure out how to change the properties of existing datetime fields. The workaround is to hide two existing date fields and then place to new date fields in a Panel to replace them. Here is the Panel's HTML code:

Code: Select all

    <div class='col-md-5'>
        <div class="form-group">
            <b>Start Date: </b>
            <div class='input-group date' id='startDate2'>
              <input type='text' class="form-control" />
              <span class="input-group-addon">
                    <span class="glyphicon glyphicon-calendar"></span>
              </span>
            </div>
        </div>
    </div>
    <div class='col-md-5'>
        <div class="form-group">
            <b>End Date: </b>
            <div class='input-group date' id='endDate2'>
              <input type='text' class="form-control" />
              <span class="input-group-addon">
                    <span class="glyphicon glyphicon-calendar"></span>
              </span>
            </div>
        </div>
    </div>


Then, call datetimepicker() on those two new fields in the JS code:

Code: Select all

$('#startDate').hide();
$('#endDate').hide();
$('#datesPanel').css('overflow', 'visible');
$("div.pmdynaform-container").css("overflow", "visible");
$("form.pmdynaform-form").css("overflow", "visible");

$('#startDate2').datetimepicker({
  format: "YYYY-MM-DD"
});

$('#endDate2').datetimepicker({
  useCurrent: false,
  format: "YYYY-MM-DD"
});

$("#startDate2").on("dp.change", function (e) {
  var newDate = moment(e.date).format("YYYY-MM-DD HH:mm:ss");
  $("#endDate2").data("DateTimePicker").minDate(newDate);
  $("#startDate").setValue(newDate);
});

$("#endDate2").on("dp.change", function (e) {
  var newDate = moment(e.date).format("YYYY-MM-DD HH:mm:ss");
  $('#startDate2').data("DateTimePicker").maxDate(newDate);
  $("#endDate").setValue(newDate);
});


LinkedDateTimeFields.png


See the attached process that shows how to implement it:
linked_date_fields-1.pmx


Thank you very much for the solution!

It works fine.

Thanks,
Yuan

cosyxu
Posts: 78
Joined: Sun Apr 03, 2016 6:39 pm
Country: Australia

Re: Improve js performance

Unread postby cosyxu » Mon Nov 20, 2017 5:59 pm

Good morning,

I would like to add jQuery Datepicker by using the following method, but I don't know how to add validation for "required field", any ideas?


Code: Select all

var datepairExample ='<div class="input-daterange input-group" id="datepairExample" style="width:98%">'
                          +'<div class="row">'
                              +'<div>'
                              +    '<div class="form-group col-sm-2 col-md-2 col-lg-2 tpl-empty"></div>'
                              +'</div>'                                         
 
                              //add validation
                              +'<div class="has-feedback">'
                                  +'<div id="d1" class="pmdynaform-field-text pmdynaform-edit-text form-group col-sm-4 col-md-4 col-lg-4 pmdynaform-field">'
                                    +'<label for="form[d1]" class="control-label pmdynaform-label col-sm-12 col-md-12 col-lg-12" style="padding-bottom: 5px; text-align: left;">'
                                        +'<span data-toggle="tooltip" data-placement="bottom" title="" class="textlabel">Start Date</span>'
                                        +'<span class="pmdynaform-field-required">*</span>'                             
                                    +'</label>'

                                    +'<div class="datetime-container">' //add class
                                      +'<div class="pmdynaform-field-control col-sm-12 col-md-12 col-lg-12" style="display:inline-table;padding-left:0px">'
                                          +'<input id="form[d1]" name="form[d1]" type="text" style="text-align: left;" class="date start input-md pmdynaform-control-text form-control" placeholder="For example: 15/09/2017" value="" autocomplete="off">'
                                          +'<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>'
                                          +'<input type="hidden" id="form[d1_label]" name="form[d1_label]" value="">'
                                      +'</div>'
                             
                                    +'</div>' 
                                  +'</div>'                               
                              +'</div>'

                              +'<div id="d2" class="pmdynaform-field-text pmdynaform-edit-text form-group col-sm-4 col-md-4 col-lg-4 pmdynaform-field">'
                                +'<label for="form[d2]" class="control-label pmdynaform-label col-sm-12 col-md-12 col-lg-12" style="padding-bottom: 5px; text-align: left;">'
                                    +'<span data-toggle="tooltip" data-placement="bottom" title="" class="textlabel">End Date</span>'
                                    +'<span class="pmdynaform-field-required">*</span>'                             
                                +'</label>'

                                +'<div class="datetime-container">' //add class
                                  +'<div class="pmdynaform-field-control col-sm-12 col-md-12 col-lg-12" style="display:inline-table;padding-left:0px">'
                                      +'<input id="form[d2]" name="form[d2]" type="text"  style="text-align: left;" class="date end input-md pmdynaform-control-text form-control" placeholder="For example: 15/09/2017" value="" autocomplete="off">'
                                      +'<span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span>'
                                      +'<input type="hidden" id="form[d2_label]" name="form[d2_label]" value="">'
                                  +'</div>'
                                +'</div>'
                              +'</div>'
                             
                               +'<div>'
                              +    '<div class="form-group col-sm-2 col-md-2 col-lg-2 tpl-empty"></div>'
                              +'</div>'               
                          +'</div>'                 
                    +'</div>';

$("#datepairExample").replaceWith(datepairExample);


I also tried to add $("#id").enableValidation(); but it doesn't work.


Thanks,
Yuan

amosbatto
Posts: 5441
Joined: Mon Jun 22, 2009 10:28 am
Country: Bolivia
Location: La Paz

Re: Improve js performance

Unread postby amosbatto » Mon Nov 20, 2017 8:10 pm

$("#id").enableValidation() will only work on a field which has its "required" property marked in the original properties of the control.

I don't recommend replacing the existing field like you are doing, because your data might not be saved correctly when the form is submitted. Add code to the form.setOnSubmit() event handler to check whether the datetime fields are empty. If so, then display an error message with alert() if empty and return FALSE to stop the submit action.
Amos B. Batto ♦ ProcessMaker Technical Documentation Writer & Forum Manager ♦ Cofounder of ILLA (http://www.illa-a.org)


Return to “Using ProcessMaker 3”

Who is online

Users browsing this forum: Google [Bot] and 4 guests