2

I have defined a beforeSubmit method in a jqGrid like this: (notice I'm using AngularJS, which provides $http service to get and post data)

beforeSumit: function(data) {
    // I need this to be filled with default data atomatically
    if(data.someField == "") {
        $http.get('defaultValue/' + data.id).success(function(getData) {
            // I put the default value into the data model returned to server
            data.someField = getData;
            // return sentence, jqGrid should continue saving without message
            return [true, null];
        }).error(function() {
            // return sentence, jqGrid should keep the edit form, showing a message
            return [false, "Couldn't get data from server"];
        });
    } else {
        // return sentence, jqGrid should continue saving without message
        return [true, null];
    }
}

What I'm doing is to check if someField is empty, and if it's empty I get a default value from server.

The problem is that return statement is throwing an undefined method error when I uses it inside the success/error of $http.get.

Is it posible to return a value there? I need to notify jqGrid if it should continue the process of saving data or not...

EDIT: Thanks to @Oleg and @Sacho comments I've realised I can't use asynchronous functions inside beforeSubmit, so finally I have put the $http call in the onselectrow event of jqGrid.

Now I need to ask the user, beforeSubmit edit form, if wants to set the default value or wants to go back to the edit form and write a custom value for the field. I can do it with a modal using $modal AngularJS's service but I'm afraid it's asynchronous too so I get the same problem than before.

Is there a way to open a modal synchronously? It doesn't matter if the browser frezees as the process won't continue until the user decides.

This is the code now:

beforeSubmit: function(data) {
    // I get this value in the onselectrow event
    var defaultValue = $scope.defaultalue;
    var modalInstance = $modal.open({
        templateUrl: 'app/partials/selectOptionDialog.html',
        controller: 'SelectOptionDialogCtrl',
        windowTemplateUrl: 'app/partials/modalTemplate.html',
        size: 'sm',
        resolve: {
            defaultValue: function() {
                return $scope.defaultValue;
            }
        }
    }).result.then(function(resolution) {
        if (resolution == true) {
            // user wants to put default value
            data.someField = defaultValue;
            // jqGrid should continue
            return [true, null];
        } else {
            // jqGrid should go back to edit form with error message
            return [false, "Please, fill the 'Archive Folder Name' field"];
        }
    });
}

The modal is a window with some test including the defaultValue and two buttons, one which closes the modal with value true (save) and other which closes the modal with value false (go back).

SOLUTION: After all, it's not posible to do what I want the way I want. Finally, I get the default value when users click a row using jqGrid event onSelectRow. I've replaced jqGrid's edit button with a custom one. What my edit button does is to check if the row has the field that I want to check empty. If so, the dialog to ask the user is shown and when the user selects an option the edit form is shown (with the field filled if user selected "Set default value" or not if selected "Another value". I have changed colModel to have the field mandatory filled, so if user selects "Another value" in the dialog and then doesn't fill the field, an error will be shown in the jqGrid.

Isthar
  • 433
  • 3
  • 14
  • What's the exact error you are getting? Your beforeSubmit function returns "undefined" if `data.someField == ""`. Your code practically looks like this: `if(data.someField == "") { /*unrelated*/} else { return [true, null]}`. Also, jqGrid doesn't accept a promise as a return value in beforeSubmit, so you're not going to have much luck trying to do an http call. – Sacho Aug 20 '14 at 09:02
  • The error is: `Uncaught TypeError: Cannot read property '0' of undefined`. It points to `jquery.jqGrid.min.js:295`, I'm using version 4.6.0 of jqGrid. You're right, jqGrid doesn't accept a promise as a return value, it needs to receive an array with a boolean and a string. – Isthar Aug 20 '14 at 09:24

3 Answers3

2

it's clear that you can't use asynchronous call to the server inside of beforeSubmit callback. You can fix your code by usage synchronous Ajax call like the usage of jQuery.ajax with async:false parameter for example, but the usage of synchronous call will block your page for some time. Mush better will be to include defaultValue in your main grid data during initial loading of the grid.

As an alternative you can makes asynchronous call inside of beforeInitData for example (it will be called buring opening of the form). You can save the results somewhere and use it later inside of beforeSubmit.

UPDATED: If you already have default value (or default values) loaded from the server then you can for example implement the following scenario:

  • if beforeSubmit discovers a problem it can change empty field to default values (the field of editing form have the same id values like name property of the corresponding column) and make the changes visible for the user. For example one can use jQuery effects (Highlight Effect, or many other) or jQuery UI effect (Highlight, Color Animation). For example one can use toggleClass with "ui-state-error" class. beforeSubmit should return error if at least one field are modified to default value.
  • At the next beforeSubmit call (after the user click "Submit" after the modification described above) it can return [true] and allow to post the data to the server.
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I've managed to get the `defaultValue` in the `onselectrow` event so I put it on the `$scope` and it's available in `beforeSubmit`. Now I need to ask the user if wants to set the default value or wants to return back to edit form. I'll use a `$modal`, is there a way to open a `$modal` synchronously? – Isthar Aug 20 '14 at 09:55
  • @Isthar: All synchronously calls are not good. In the most scenarios one can solve the problem in other way. For example you can use custom field validation (see [the documentation](custom_checking_example)). Alternatively you can **modify** some form fields inside of `beforeSubmit` callback and mark it in some ways like adding `"ui-state-error"` class (or other) or/and usage some kind of [effects](http://api.jquery.com/category/effects/) (fadeIn, animate etc). In the way you can display error message and modify form filed at the first call of `beforeSubmit` and just return `[true]` later. – Oleg Aug 20 '14 at 11:09
  • Thaks @Oleg. I got it, I can't do what I want the way I want :) I'll replace the button to show edit form by a custom one and I'll show first of all the dialog asking the user, then the form with the field filled or not depending on the selection of the user. – Isthar Aug 20 '14 at 11:38
  • 1
    @Isthar: You are welcome! Custom button is one more alternative. You can for example hide the original button and trigger "click" on the button inside of `click` event handler of your custom button. There are many other options too. – Oleg Aug 20 '14 at 11:44
  • 1
    @Isthar: See [the demo](http://www.ok-soft-gmbh.com/jqGrid/NewButtonInEditFormAndHideOld.htm) which is simple modification of the demo from [the answer](http://stackoverflow.com/a/10324302/315935). – Oleg Aug 20 '14 at 11:51
  • that's perfect! Simply adding a button to fill default value. Thank you! – Isthar Aug 20 '14 at 14:44
1

If jqGrid supports a beforeSubmit that returns a promise (that is to say, an asynchronous beforeSubmit), then @Pam is correct. If not, as @Sacho says, then you need the promise to already be resolved when beforeSubmit is executed. The only way to ensure that is to write beforeSubmit inside the promise's callback.

$http.get('defaultValue/' + data.id).success(function (defaultValue) {
    /* all the code dependending on this defaultValue variable should go here */
    ...
    beforeSubmit: function (data) {
        if (data.someField == "") {
            data.someField = defaultValue;
            return [true, null]
        } else {
            ...
        }
    },
    ...
})
.error(function () { /* handle network or server-side error */ }
Hugo Wood
  • 2,140
  • 15
  • 19
  • I have simplified the code because of confidentiality terms, but I need the edited data to get the default value, so I can't get it before the `beforeSubmit`. – Isthar Aug 20 '14 at 09:26
  • 1
    Ah yes, you need `data.id` for the URL...Well then you have several solutions: 1) pre-fetch all default values, if that's possible 2) make a synchronous HTTP request instead of an asynchronous one, using bare-bone XHR because [Angular's $http can't do it](http://stackoverflow.com/questions/13088153/how-to-http-synchronous-call-with-angularjs) 3) modify jqGrid so it supports an asynchronous `beforeSubmit` 4) swap jqGrid with a library that supports it. – Hugo Wood Aug 20 '14 at 09:42
0

Since $http promise is being returned, I think you need to change the $http.get(..) to return $http.get(..).

Also note that, using .success() will return the original promise and .then() will return a new promise. Since each call would be returning a new promise, .then() would be driving the sequential operations.

Pramod Karandikar
  • 5,289
  • 7
  • 43
  • 68
  • Actually, `$http.get(..)` returns a promise, but I can't realize when it has been returned to get it's value. – Isthar Aug 20 '14 at 09:18