3

I am using a jqgrid where I'd like to use inline editing and mask the entry such that the user is prompted to enter hh:mm where hh = hours and mm = minutes. I'm using the digitalBush masked jquery plugin. The issue is that when I call it from initData, it overwrites the current data in that field. I noticed that this behavior is different when you use a modal form to do the editing. Does anyone have a solution for this issue? I'll call the mask from any event, and I'm happy to use any available plugin. As far as I can tell, the jqgrid formatter does not provide a custom mask that guides the user entry in the format in which I need it. Also happy to be wrong about that (with a snippet of code to support it of course).

Thanks so much in advance.

Update: I managed to cobble together a demo of the problem I'm having. S-O obviously strips out the html that I wanted to wrap this in so that it could be plugged in and run as-is, so you'll need to wrap this in some html to see it work. Thanks again for the assistance. Here's the code:

    <title>Mask Problem</title>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.2.0/css/ui.jqgrid.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.maskedinput-1.3.min.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.2.0/js/i18n/grid.locale-en.js"></script>
<script type="text/javascript" src="http://www.ok-soft-gmbh.com/jqGrid/jquery.jqGrid-4.2.0/js/jquery.jqGrid.src.js"></script>
    <script type="text/javascript">
        $.jgrid.no_legacy_api = true;
        $.jgrid.useJSON = true;

</script>
<script type="text/javascript">

    $(function () {
        var lastSel = -1;
        var mydata = [
            { HoursWorked: "0:00" },
            ];
        $.mask.definitions['5'] = '[0-5]';
        $.mask.definitions['2'] = '[0-2]';
        var $grid = $("#MyGrid");
        $grid.jqGrid({
            datatype: "local",
            data: mydata,
            height: 'auto',
            width: 700,
            colNames: ["Hours Worked"],
            colModel: [
                    { name: "HoursWorked", index: "HoursWorked", width: 85, editable: true, edittype: "text", editoptions: { size: 20, maxlength: 30,
                        dataInit: function (elem) {
                            $(elem).mask("29:59");
                        }
                    },
                        align: "center", editrules: { custom: true, custom_func: validHourEntry }
                    }
                  ],
            multiselect: false,
            caption: "My sample grid with Mask",
            rowNum: 10,
            cellEdit: true,
            rowList: [5, 10, 20],
            pager: '#MyGridpager',
            gridview: true,
            beforeSelectRow: function (rowid) {
                if (rowid !== lastSel) {
                    $(this).jqGrid('restoreRow', lastSel);
                    lastSel = rowid;
                }
                return true;
            },
            cellsubmit: "clientArray"
        }).jqgrid("navGrid", "#MyGrid", { add: false, del: false }); ;
    });




function validHourEntry(value, colname) {
    var editSuccess = true;
    var errorMsg = "";
    if (/^([0-1][0-9]|2[0-3]:[0-5][0-9])$/.test(value)) {
        return [true, ""];
    } else {
        return [false, "is wrong time.<br/>Please enter the time in the form <b>hh:mm</b>"];
    }
}


</script>
Ron
  • 867
  • 11
  • 26

1 Answers1

8

You don't posted any code, so I tried to use digitalBush masked jQuery plugin for editing of hours myself. It seems good work and I received

enter image description here

in inline editing or

enter image description here

in the form editing.

I implemented this in the following way. First of all I defined two masks: one to enter digits from 0-2 and the next mask to enter digits from 0-5:

$.mask.definitions['2']='[0-2]';
$.mask.definitions['5']='[0-5]';

and used the following definition of 'time' column in the grid:

{name: 'time', index: 'time', width: 70, editable: true,
    editoptions: {dataInit: function (elem) { $(elem).mask("29:59"); }},
    editrules: {time: true}}

I added time validation with respect of editrules: {time: true} to prevent to enter the time like 27:20. Becease the standard time validation display not perfect error warning

enter image description here

we can improve the results using custom validation:

{name: 'time', index: 'time', width: 70, editable: true,
    editoptions: {dataInit: function (elem) { $(elem).mask("29:59"); }},
    editrules: {custom: true, custom_func: function (value) {
        if (/^([0-1][0-9]|2[0-3]:[0-5][0-9])$/.test(value)) {
            return [true, ""];
        } else {
            return [false, "is wrong time.<br/>Please enter the time in the form <b>hh:mm</b>"];
        }
    }}}

which changes the validation error message to the following

enter image description here

I am sure that you can improve the visibility with another customization of the mask plugin and validation. In any way my experiments show that one can do use successfully mask plugin in jqGrid.

You can see the demo here.

UPDATED: Sorry Ron, for writing of that, but the code which you posted is really good example how one should not write the program and how one should not use jqGrid. At the beginning I don't wanted to write any comments, but later I do decided to describe you what is wrong in the code and explain how one should modify the code.

The first problem in your code is that you used object class SampleJSObject instead of direct usage of functions. From the syntax how the constructor and the methods of an object should be defined the code is correct, but ...

  • Which sense hast to make some general global settings inside of the object constructor. Yo used $.mask.definitions['5'] = '[0-5]'; for example. Every create of the instance of SampleJSObject the global settings will be set or overwritten. It looks like side effects.
  • You defined function SampleJSObject on the top level of your code and not inside of $(document).ready where you use it, so you defined global class.
  • Inside of $(document).ready you defined uninitialized variable lastSel and try to initialize it inside of function SampleJSObject defined in another scope. So the variable lastSel stay uninitialized in $(document).ready, but you set another global variable lastSel inside of the constructor.
  • The methods like minutesToHours has nothing to do with your class SampleJSObject. Why the function or calculateHoursAndMinutes should be member of the class? It's error in design in my opinion.
  • The method init set only the jqgridParms property. You can do it in the same way in the constructor, but in both cases it is not clear for me why one need and method which defines so specific parameters like you do. I don't think that you will be create more then one instance of such specific class. Why one need have such class where you will have to overwrite almost any method to create the second instance of the class?
  • In the list of parameters of jqGrid you use datatype: "local", but not use gridview: true and data parameter which allows to create the data together with grid. It improve the performance of grid in many times especially for grids with the large number of rows. The usage of addRowData in loadGrid in an example of the most slow method. Moreover in the case the rowNum: 10 will be ignored and no local paging will be done.
  • the method calculateTotal demonstrate probably the most slowest implementation of the virtual WeekTotal column. The most effective implementation of the feature would be the usage of custom formatter for the WeekTotal column

    { name: "WeekTotal", index: "WeekTotal", width: 55, align: "center" , formatter: function (cellvalue, options, rowObject) { /* here you can access the other columns of the same row just as rowObject.SundayMinutes and return from the function the calculatedWeekTotalvalue as string of HTML fragment */ }}

  • If you nee to use many columns with the same properties you can define the column template (see here):

    var myTimeTemplate = {width: 85, editable: true, edittype: "text", editoptions: { size: 20, maxlength: 30, dataInit: function (elem) { $(elem).mask("29:59"); }}

    and then reduce the definition of the column SundayMinutes for example to

    {name: "SundayMinutes", template: myTimeTemplate }

Community
  • 1
  • 1
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • when you exit the field in your example without filling in a complete entry (ie, enter 20 and leave the minutes blank), the text field displays blank. In my code, it leaves the remainder of the mask so it would be 20:__. When I tab through the field, the mask gets set and left as __:__. That's the issue I need to solve. I think you're solving it by resetting the row data. I need to reset the cell value if no entry is made. – Ron Dec 08 '11 at 03:43
  • @Ron: Could you say how many money I have now in my pocket? You can't? Exactly in the same way nobody can help you to find the error in your code if you don't show the code. You can examine the source code of [my demo](http://www.ok-soft-gmbh.com/jqGrid/MaskedInputHours.htm) and compare with the way how you use it. Do you included any validation rule for example? – Oleg Dec 08 '11 at 06:28
  • My comment is that in your demo, your entry gets blanked out if it is not complete. That's essentially the issue I'm also having - I want it get caught in the validation, but it does not. To recreate, jump into the field, enter "20" (no quotes of course) then tab out of the field. So, to extend your analogy, I'm asking you to count the money in your own pocket. – Ron Dec 08 '11 at 13:22
  • I also should mention that I'm tagging you (@Oleg) with each comment but stackoverflow seems to strip it out when I save it. – Ron Dec 08 '11 at 13:29
  • @Ron: First if you write comment to *my* answer you don't need to write `@my`. The text will be deleted to save the restricted place for the comment. About your problem I still not full understand what you mean. In the text of your question you wrote: **"The issue is that when I call it from initData, it overwrites the current data in that field."** In my demo the initial data from the cell will be not changed by plugin. The only thing which I can see is that on the error message one see the mask. Is it what you mean or you have another problem? An screenshort with the problem could be helpful – Oleg Dec 08 '11 at 14:18
  • I have added a demo that displays the problem. If you tab/click into Sunday and then tab out of the field, the entry becomes the mask, instead of the original value. And, you're correct - I was mixing up two different problems. I suspect fixing this one will fix the other. – Ron Dec 09 '11 at 14:53
  • @Ron: I updated my answer with some remarks to your code. The code itself I didn't tested. – Oleg Dec 09 '11 at 23:38
  • Thank you Oleg. What you don't understand is that I'm working on a project and have implemented jqGrid the specific way I was instructed to do it -- this is the first time I've used jQuery, much less a plug-in. I put together this demo code to display a particular problem, and, yes, in my haste to put together a sample of the problem I'm having, I didn't clean up the code as well as I should've. However, you'r comments don't address the problem and I wouldn't become a trainer using the tone you use. I've found your attitude demeaning and decidedly unhelpful – Ron Dec 12 '11 at 14:16
  • @Ron: Sorry, I didn't want to insult you. I wanted only point you the places of the code which are not good. If you ask a question you should think not about your existing code. It would be kind to other who will read your question to simplify the code so that *your real problem* which you has will be clear seen. For example, you could test whether the problem exists with *one masked input* and reduce the code having one mask per the day of the week. The mission of stackoverflow is to share good questions and its solutions. Please think about the value of your question for later visitors too. – Oleg Dec 12 '11 at 15:17
  • Thank you. I'm trying to only ask questions of value, and I assume if there's no value, there'll be no answer. At the same time, those people answering questions should consider that they are not the sole arbiter of all code written. In my case, I have a very strict guideline which I MUST follow if I wish to continue receiving a paycheck. I don't have the experience to defend this approach, all I know is I have to use it. So, I appreciate your feedback and will consider it very strongly when I'm in a position to do as I wish, but right now, I need to solve the original problem. – Ron Dec 13 '11 at 21:14
  • And, I should add, the original problem is this: if you click into the entry field (only one now), the value will immediately change to the mask characters. If you tab out of the field, you will get an alert that your entry is not valid, then you'll get the original value. My desired behavior is that the value not change if I don't key anything. – Ron Dec 13 '11 at 21:15
  • @Ron: You don't posted the code of `timeEntryFormat` and you used undefined `self` in the code. Could you explain what exactly the problem exist in [the demo] which consist from your code after removing undefined variables or functions? – Oleg Dec 19 '11 at 23:33
  • I fixed the code. The problem is that when you click on the enterable field (0:0), it changes to the default mask value (underscores). If you tab out of the field or click out of the field, the validation catches the entry as incorrect. In your demo, when I double-click the field to edit it, the original value remains until I key something. If I key a backspace, I see the mask and the field changes to blank until I click on a different row. Then, it reverts to the original row. I suspect that's your beforeSelectRow function. I need that behavior, but when the person leaves the cell. – Ron Dec 21 '11 at 15:47
  • @Ron: Sorry, but in my previous comment the link to the [new demo](http://www.ok-soft-gmbh.com/jqGrid/MaskedInputHours_.htm) was corrupted. The demo is a simple modification of youth demo. Now to your last comment. I suppose now that all you problems come from misunderstanding what masked plugin do. The value "0:00" which you use **is wrong** corresponds to the mask. It must be "00:00". It have to have exactly 4 characters. The time "6:25" *must be* entered as "06:25". – Oleg Dec 21 '11 at 16:03
  • the problem with doing a lot of new stuff is that you can make the same dumb mistakes....After all that. Thank you for your help and again thank you for all of your comments. – Ron Dec 22 '11 at 13:53
  • For everyone else - there are a lot of comments but if you're new to jqgrid and jquery (like me - new to everything client side), read @Oleg's comments on my code too. I am learning a lot. – Ron Dec 22 '11 at 13:54
  • @Ron: You are welcome! I am glad, that the problem is solved at the end. Congratulations! – Oleg Dec 22 '11 at 13:56
  • @Oleg, what amazing answer, thanks for your effort works like a charm :) – rubdottocom Mar 05 '12 at 14:31
  • @rubdottocom: You are welcome! By the way you have right to vote about 30 helpful answers/question **per day** (see [here](http://meta.stackexchange.com/a/5213/147495)). Voting helps other visitors of the page and help to find the page during searching on the stackoverflow. – Oleg Mar 05 '12 at 14:43