free-jqgrid / jqGrid

jQuery grid plugin
https://github.com/free-jqgrid/jqGrid
Other
480 stars 195 forks source link

New feature request: for Add form, enable pull of 'new' data with intermediate ajax request #282

Closed bjd-pfq closed 7 years ago

bjd-pfq commented 7 years ago

New feature request: for addRow form, enable one to pull data from another PHP file (that basically, in turn, retrieves it from a non-local server), to be entered into the form as rowId 'new'.

Example: I have a grid with books (title, author, ISBN, classification, and some 50 other fields). Upon Add click, I get my modal Add form.

Now what I would like to do is enter ISBN (with barcode scanner), Submit the form (this is the 1st Submit, and the form does not pop down), PHP with a curl call fetches a record from say the MARC21 public service by the Library f Congress. The record is returned, and entered into the form with some simple javascript. This form, after review and maybe custom edits and additions, then is submitted a second time (same or other PHP url), this time for addition to the database and to the grid.

That is the basics. I have implemented this to a large degree, in an afterSubmit_function. My solution is kinda 'hacky'(1) and incomplete(2) though:

  1. It has to submit the POST data twice to the same PHP file. I tried to modify url dynamically, just before the second submit, but I could not get that to work. Submitting to the same PHP file is not so bad though, you just have to look for some added field in the POST data, and current jqGrid allows me to add such a marker field. So this is not that big a problem, (2) is a show stopper:

  2. For some or actually quite a few ISBN's, multiple records can be returned by the external server, from which only ONE should eventually be chosen to be added to the database. In my current hack, I just blindly take the first in the returned json array, and display that in the form. I tried to enable the pData and nData paging buttons in the Add frm (like they are present in the Edit form), and hang some callbacks off of them, but couldn't get that to work. I'm not a great hero in either js or jquery. If that worked, when nData would be pressed, record no.2 that was received from the server would be shown in the form, etc. When Submit would be clicked for the 2nd time, the record currently in view in the form would be the chosen one to be submitted to the grid, and the form would pop down.

I thought such a scenario might occur more often. Does all this make sense?

OlegKi commented 7 years ago

I find your request interesting in general, but I want to clarify some things. First of all, you wrote once about addRow method and then about some "forms" (see "modal Add form" for example), which exist only in case of usage editGridRow (form editing). Which editing mode you use: inline editing or form editing?

You write about intermediate ajax request. It can be easy realized by usage of event handlers in the ISBN field like change or input. Alternatively one can add "Search in MARC21" icon/button at the end of ISBN filed inside of dataInit callback for example. You can fill/overwrite the content of other field with the data returned from the MARC21 public service by the Library of Congress. I don't use such service myself, but you can prepare a small demo in JSFiddle, which use free jqGrid and the MARC21 public service and I could help you to integrate both in editing.

bjd-pfq commented 7 years ago

Thank you for your answer. I am using form editing only. I am sorry for the confusion.

I hadn't thought of the input event handling, I'll see what can be achieved in that way. But my main problem was the paging through the json-array of records returned from the LOC-call, to select one for Submit, because the Add form doesn't have the paging buttons (like the Edit form has them).

OlegKi commented 7 years ago

It's better if you post a demo or at least an example of typical request to the "MARC21 public service by the Library of Congress". I wrote that I don't use it, don't know the exact URL and so on. It's unclear for me how many rows of data (10, 100, 1000, ...) you need to display for choosing by the user inside of jqGrid edit form. I personally used to use select2 (see https://select2.github.io/ and https://github.com/select2/select2), which can be easy integrated in jqGrid edit form (see the answer http://stackoverflow.com/a/37876387/315935). It allows to display relatively large set of data and easy to find the correct item from the choices (see examples https://select2.github.io/examples.html). The select2 allows to reduce the list of items by typing searching term. I seems to me very close to your requirements.

bjd-pfq commented 7 years ago

Records from LOC can be obtained with the Yaz plugin for PHP. Calls could be made like this:

function yaz_test( $ISBN )
{
    $z = yaz_connect( 'z3950.loc.gov:7090/voyager' );
    yaz_range( $z, 1, 1 );          // show results starting with 1 and for a total of 1
    yaz_search( $z, 'rpn', "@attr 1=7 " . $ISBN );           // 7=ISBN; 4=title words
    yaz_wait();
    $error = yaz_error( $z );

    if (empty( $error ))
    {
        $hits = yaz_hits( $z );
        $rec = yaz_record( $z, 1, 'string' );
        //echo $rec;
        // Parse the retrieved MARC record with File_Marc PHP plugin
        //$marc_file = new File_MARC( $rec, File_MARC::SOURCE_STRING );
    }
    yaz_close( $z );        // close the YAZ connection
}

Example of a record returned, as 'string':

01348cam  2200337 a 4500
001 4926180
005 20130712135148.0
008 950719s1996    njua     b    000 0 eng  
035    $9 (DLC)   95035582
906    $a 7 $b cbc $c orignew $d 1 $e ocip $f 19 $g y-gencatlg
955    $a pb16 to ja00 07-19-95; je39 07-26-95; 27Jul95 JE08 to SL; je05 to DDC 07-27-95; CIP ver. pv07 02-22-96
010    $a    95035582 
020    $a 0691037914 (cl : alk. paper)
040    $a DLC $c DLC $d DLC
050 00 $a QC173.59.S65 $b H4 1996
082 00 $a 530.1/1 $2 20
100 1  $a Hawking, Stephen, $d 1942-
245 14 $a The nature of space and time / $c Stephen Hawking and Roger Penrose.
260    $a Princeton, N.J. : $b Princeton University Press, $c c1996.
300    $a viii, 141 p. : $b ill. ; $c 24 cm.
440  4 $a The Isaac Newton Institute series of lectures
504    $a Includes bibliographical references (p. [139]-141).
650  0 $a Space and time.
650  0 $a Quantum theory.
650  0 $a Astrophysics.
650  0 $a Cosmology.
700 1  $a Penrose, Roger.
856 41 $3 Table of contents $u http://www.loc.gov/catdir/toc/prin031/95035582.html
856 42 $3 Publisher description $u http://www.loc.gov/catdir/description/prin021/95035582.html
920    $a ** LC HAS REQ'D # OF SHELF COPIES **
991    $b c-GenColl $h QC173.59.S65 $i H4 1996 $p 00023761373 $t Copy 1 $w BOOKS

This can be parsed further with the File_MARC plugin for PHP.

I also make searches for 'title' (for books without ISBN), where the return by LOC can easiy be multiple records.

Note that I have a local PHP-script which performs this LOC-search, and the parsed results (with File_MARC) will be returned as json to the jqgrid Add form, which currently then only takes the first item in that array.

bjd-pfq commented 7 years ago

To clarify, this is the sequence:

Create grid
Click 'Add' in navGrid
Add form pops with number of fields, amon which title, isbn
Enter ISBN or some title words into their fields
Click Submit (1st time); the Add form does NOT pop down  (or click an extra added button, there is no problem to implement this, this is not the issue)
ajaxRequest goes to fetch-record.php
    fetch-record.php issues yaz-request to LOC, parses results, encodes them as json array (1 or more records, let's say with a max. of 8)
    fetch-record.php returns this json as response to the ajaxRequest (let's say it returns 3 records in this example)
Add form javascript code fills form with the first record from the json (that contains 3 records)
--
Add form also places Prev and Next buttons for the user to see the other 2 records (*
User can page through the 3 records and their full data, to see which one should be added to the grid, based on a review of the data (e.g. "is this the edition that I want")
After going forward and back reviewing, user has made a decision, and when the wanted record is in view, user simply clicks Submit (2nd time)
    record is added to the grid, Add form pops down

*) the paging might prob. be better handled by the PHP side upon a click on Prev or Next button, but that is not an issue here

I have implemented this up to where the two dashes are. Actually, I have also placed the paging buttons, but their functionality, as for example the Edit form does, I haven't succeeded in implementing; it seems I would need to duplicate a major part of the edGridRow function just to implement them, but like I said, I am not a great hero in js or jq.

OlegKi commented 7 years ago

Sorry, but we should speak in the same language first of all. I asked you to post me the URL (with parameters), which would be typical for the request for ISBN, which you described. I see only z3950.loc.gov:7090/voyager with unknown additional parameters in you last comments. I asked you: "how many rows of data (10, 100, 1000, ...) you need to display for choosing by the user inside of jqGrid edit form". You didn't answer on the question.

jqGrid is pure JavaScript library and you post me fragments of PHP code of plugins and some binary code instead. I don't use PHP at all. I used to use C# or early C/C++ and other more seldom languages. The JavaScript code, for example, an example of jQuery.ajax request to the "MARC21 public service by the Library of Congress" would be good. One can use Developer Tools of web browsers (IE, Chrome, Firefox, ...) and to make trace of HTTP traffic in the Network tab of the Developer Tools. One will see the URL with all parameters, which will be sent to the MARC21 service and the corresponding JSON response. The information could be interesting for me, but not a binary data.

I suggested you additionally to use select2. You can make separate Ajax request to MARC21 server and to fill select2 with the results or you can use select2 option for the remote request (see the example). Do you tried select2? Is it close to your requirements?

bjd-pfq commented 7 years ago

The following is for your information only, and I won't press this issue any further, since this discussion has stagnated.

"Z39.50 is a pre-Web technology" not HTTP and certainly not REST based. But that was not relevant, anyway, since the results from the LOC-search are presented by a local server PHP file as json, like I said. For example:

1 result returned for a seach on ISBN 0-691-03791-4:

[{"id": "new","titel": "The nature of space and time; The Isaac Newton Institute series of lectures","auteur": "Stephen William Hawking; Roger Penrose","jaar": "1996","uitgever": "Princeton, NJ : Princeton University Press","annotatie": "Met lit. opg","omvang": "viii, 141 p.","illustratie": "ill.","formaat": "25 cm","isbn": "0-691-03791-4 (cl) : alk. paper, 0-691-05084-8 (pbk)","trefwoord_goo": "Relativiteitstheorie, Kwantumveldentheorie","basisclassificatie": "33.20 modern klassieke fysica: algemeen"}]

Another example: A search on title words 'russian folklore', 3 results:

[{"id":"new","titel":"The image of Ivan the Terrible in Russian folklore; Cambridge studies in oral and literate culture","auteur":"Maureen Perrie","jaar":"1987","uitgever":"Cambridge [etc.] : Cambridge University Press","annotatie":"Lit. opg.: p. 254-261, en index","omvang":"x, 269 p.","illustratie":"ill.","formaat":"24 cm","isbn":"0-521-33075-0","trefwoorden":"Ivan IV Vasil\u02b9evic\u030c tsaar van Rusland (1530-1584)"},{"id":"new","titel":"The study of Russian folklore; Slavistic printings and reprintings. Textbook series ; 4;; Indiana University Folklore Institute monograph series ;; vol. 25","medewerker":"Felix Johannes Oinas; Stephen Soudakoff","jaar":"1975","uitgever":"The Hague [etc.] : Mouton","annotatie":"Lit. opg","omvang":"X, 341 p.","formaat":"25 cm","trefwoord_depot":"Rusland; Volkenkunde","trefwoord_goo":"Volksmuziek; Rusland","basisclassificatie":"24.70 etnomusicologie"},{"id":"new","titel":"Folk-lore and legends : Russian and Polish; Folk-lore and legends. 2nd series ; 3","jaar":"1890","uitgever":"London","formaat":"8\u00b0"}]

In addition, I am sending two screenshots of an Add form, 1. where an ISBN is entered, and 2. where, after SUBMIT had been clicked, the returned json has been placed inside the Add form fields. The paging buttons are dummies.

screenshot-20170111-002952 screenshot-20170111-003007

I don't see how how I could use select2.

OlegKi commented 7 years ago

Could you post JSFiddle demo (or some other demo), which do what you posted as images? I posted you some demos (see my previous comments), which shows how to integrate select2 in jqGrid. In general you should just define edittype: "select" and to initialize select2 inside of dataInit. It convert the standard <select> to more advanced control. I posted you before the reference, which shows how select2 can makes Ajax request to an remote server. Just try to type something in the demo and see the results, which select2 displays. The demo uses templating, which you can see on another demo. Templating allows to specify in easy way which custom information you want to display in every item. Select2 support events, which allows to do custom action, for example, if the user choose an item from the list. See the demo from the section of documentation. You can choose an item in the demo and you will see Log of data.

You'll get the details of the user's choice inside of "select2:select" event handler. The only step, which you will need to do will be setting of all fields of Edit for of jqGrid. The ids of the fields are the same as the name value of the columns in colModel. Thus you will need just to make a mapping of the properties of JSON response to the column names and to set the fields of the Edit form in the loop.

OlegKi commented 7 years ago

I forgot to mention that I'd recommend you to use rowpos and colpos properties of formoptions to place the items of the form in multiple columns. See the demo created for the old answer. The resulting edit form looks like on the picture below: picture

OlegKi commented 7 years ago

@bjd-pfq Do you have any progress in the issue? Did you try my last suggestions?

bjd-pfq commented 7 years ago

I was trying to complete my code, and then maybe to create an example. Since my case is quite complex, and since I cannot easily create a fiddle or anything like that (since it's quite hackish the way I have it now), I was intending to first create a video of an 'Add' procedure.

But I understand that I can place a URL here to DropBox, to a short video of the procedure. Do you know?

bjd-pfq commented 7 years ago

This is what I have right now:

https://www.dropbox.com/s/i35jbzl7izbo0pk/add.mp4?dl=0

It is a rather terrible hack with the added Prev/Next pager buttons beforeShowForm functions, afterShowForm, beforeSubmit, AfterSubmit, synthetic submits (intercepting clicks on SUBMIT) to retrieve the data that the PHP server will then retrieve from another remote server, etc.

The example shows an ISBN being entered, and being submitted (with marker data to distinguish it from a true SUBMIT to the database); then a local PHP script does a lookup on this ISBN to an external server, packs the result in a json array, and returns it to the Add-form.

In this case, the result consists of 2 records, so the json has 2 records. So these are two records of the same ISBN, with variations in the description of the book (the PPN is a sort of unique Production Number of the library, but it is not important in this case; I need to add on the form some text like '1/2' etc. that changes when paging).

The user then has to decide which description to take (which of the two records to take) and submit that one finally to the database. (The descriptions vary because it's a human work, some librarians put more effort than others into describing in book). So what is submitted is a complete record, in this case it's either the first, or the second. So that's why I cannot see how I could use select boxes.

My original thought, after having migrated my project to jqGrid a few weeks ago, was this: the Add-form in my case, when it has to be able to retrieve data, and then handle >1 results, is in an abstract way like a 'grid' itself, though with a different, more user-friendly layout; or maybe it's a sequence of 'View's (like you have implemented standard in the jqGrid).

OlegKi commented 7 years ago

If I correctly understand what you want to implement, you need that the click on Add button will display the form wich one ISBN field only. If you want to search for another fields like title then you can include the Title field additionally to ISBN field. In any way, in my understanding of your requirements, you need to use addfunc callback of navGrid (like in the demo from the old answer) or just to use add: false option of navGrid and to add "+" (custom Add) button using navButtonAdd. In both cases if the user will clicks on "+" button you can create custom Add form with one or small set of fields, which you want allow for searching. After the user choose the ISBN or the searching term you can make Ajax request to the server and fill new grid with the data, returned from the server. You can call editGridRow, or viewGridRow, with rowid of the first row of the second grid. The resulting Edit/View form will look like on your demo. If you use View form, that you can use beforeShowForm to add custom button to the grid. After the user choose the item you can use the data from the second grid to add new row to the first grid.

To understand how adding of custom button of the View form work you can add view: true to the option of navGrid and to use the following formViewing options (the options of View form):

formViewing: {
    beforeShowForm: function () {
        $('<a tabindex="0" role="button"><span class="fm-button-icon fa fa-check"></span><span class="fm-button-text">Choose</span></a>')
        //$('<a href="#">Save and New<span class="ui-icon ui-icon-disk"></span></a>')
            .click(function() {
                alert("The row with the rowid=" + $("#id_g").val() + " is choosen.");
                $("#cData").click(); // trigger click on the Close button
            }).addClass("fm-button ui-state-default ui-corner-all fm-button-icon-left")
                .prependTo("#Act_Buttons>td.EditButton");
    }
}

You should have the View form close to the following: v1

OlegKi commented 7 years ago

@bjd-pfq: I didn't get any comment from you since 5 days. Do you have any progress of implementation of your requirements? You should close the issue if your question is cleared now.

bjd-pfq commented 7 years ago

Thanks. I failed to explain exactly my idea, so I will close this now.