Announcement

Collapse
No announcement yet.

Miva 9 Bartch Screens (like Categories)

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Miva 9 Bartch Screens (like Categories)

    Is there sample code for implementing a Miva 9 style batch screen. I'd love to have the new Miva 9 interface in my Map Locations module.

    I see ui.mv has features like DrawTabs() and others but don't really document their usage.
    Last edited by RayYates; 12-28-15, 11:40 AM.
    Ray Yates
    "If I have seen further, it is by standing on the shoulders of giants."
    --- Sir Isaac Newton

    #2
    Re: Miva 9 Bartch Screens (like Categories)

    Yes on this page:

    http://www.miva.com/docs

    Under the User Interface Documentation there is a pdf which has docs on how to implement this into your modules:

    http://www.miva.com/pdf/mmbatchlist.pdf
    Last edited by Brennan; 12-28-15, 09:37 AM.
    Brennan Heyde
    VP Product
    Miva, Inc.
    [email protected]
    https://www.miva.com

    Comment


      #3
      Re: Miva 9 Bartch Screens (like Categories)

      Cool! Thanks Brennan
      Ray Yates
      "If I have seen further, it is by standing on the shoulders of giants."
      --- Sir Isaac Newton

      Comment


        #4
        Re: Miva 9 Bartch Screens (like Categories)

        The pdf files are pretty sparse and only provide the most rudimentary examples. Digging into the resulting .js files in the admin indicates there are many hundreds of JavaScript API functions and prototype methods. The file mmbatchlist.js provides little insight into usage of these methods.

        An explanation of the methods would be very useful. This is only a partial list:

        .SetDisplayInMenu( false )
        .SetDisplayInList( false )
        .SetSearchable( false )
        .SetSimpleSearchEnabled ( false )
        .SetAdvancedSearchEnabled( false )
        .SetSortByField( 'disp_order' )
        .SetOnRetrieveValue( onretrievevalue )
        .SetWidth( '50px' )
        .SetUpdateOnModifiedOnly( update_on_modified_only )
        .SetOnRetrieveValue ( onretrievevalue )
        .SetOnSetValue( onsetvalue )
        .SetOnParseEditableColumn()
        .SetOnDisplayFieldError()
        .SetOnDisplayData()
        .SetOnDisplayEdit()
        .SetOnExportData()
        .SetSortByField( sortby )
        .SetSortByText( text )
        .SetFieldName()
        .SetDefaultActive()
        Ray Yates
        "If I have seen further, it is by standing on the shoulders of giants."
        --- Sir Isaac Newton

        Comment


          #5
          Re: Miva 9 Bartch Screens (like Categories)

          Originally posted by RayYates View Post
          The pdf files are pretty sparse and only provide the most rudimentary examples. Digging into the resulting .js files in the admin indicates there are many hundreds of JavaScript API functions and prototype methods. The file mmbatchlist.js provides little insight into usage of these methods.

          An explanation of the methods would be very useful. This is only a partial list:

          .SetDisplayInMenu( false )
          .SetDisplayInList( false )
          .SetSearchable( false )
          .SetSimpleSearchEnabled ( false )
          .SetAdvancedSearchEnabled( false )
          .SetSortByField( 'disp_order' )
          .SetOnRetrieveValue( onretrievevalue )
          .SetWidth( '50px' )
          .SetUpdateOnModifiedOnly( update_on_modified_only )
          .SetOnRetrieveValue ( onretrievevalue )
          .SetOnSetValue( onsetvalue )
          .SetOnParseEditableColumn()
          .SetOnDisplayFieldError()
          .SetOnDisplayData()
          .SetOnDisplayEdit()
          .SetOnExportData()
          .SetSortByField( sortby )
          .SetSortByText( text )
          .SetFieldName()
          .SetDefaultActive()
          Hey Ray,

          Here's a brief explanation of each. Let me know if you need more explanation.

          Code:
          MMBatchList_Column functions
              SetDisplayInMenu( true | false )
                  Default is true, so there is really no need to call SetDisplayInMenu( true ). Calling SetDisplayInMenu( false ) will hide the column from the "Show/Hide Columns" menu. This basically allows you to force a column to either always be visible in the list, or always be hidden (when used in conjunction with SetDisplayInList)
          
          
              SetDisplayInList( true | false )
                  Default is true, so there is really no need to call SetDisplayInList( true ). Calling SetDisplayInList( false ) will hide the column from the mmbatchlist (you will still see it in the menu if you don't call SetDisplayInMenu( false )). There are two main reasons to use this. The first would be to make a column sortable but not visible (sorting by an ID would be an example of this. You don't want to display the id, but it would be nice to sort by it). The second reason to use this is for search purposes... Occasionally, a list will need to display one set of data, while allowing you to search for something else. In cases like this, you would have a non-searchable column visible that shows your data, and then have one or more columns that are visible only in advanced search. Take the Product Attribute batchlist as an example. We only show the code/prompt columns in the list and we don't differentiate between attribute and option, but if you open the Advanced Search dialog there exists four columns instead of two: Attribute Code, Attribute Prompt, Option Code, and Option Prompt. 
          
          
              SetSearchable( true | false )
                  Columns are searchable by default. SetSearchable( false ) will disable all search functionality (simple, find in list, AND advanced search)
          
          
              SetSimpleSearchEnabled( true | false )
                  Enabled by default. Enables/Disables Simple Search only (which also enables/disables Find In List) for a given column. This is useful if you want to have a column that is advanced-searchable but NOT searchable from the input field on the list itself (you would, for example, use this in the above example for SetDisplayInList).
          
          
              SetAdvancedSearchEnabled( true | false )
                  Enabled by default. Enables/Disables Advanced Search only for a given column. This is useful if you want to have a column be simple searchable (from the search input on the batchlist), but NOT searchable when viewing the advanced search dialog.
          
          
              SetSortByField( field_name )
                  The sort by field name is the string value passed to the backend JSON function used for that column's sort. For example, if I wanted to sort the column based on the "id" value, I could pass "id" as the field_name and any time I sorted by that column, we'd pass "id" as the sort by field. You would then handle this on the back end via SQL_Query_OrderBy_Fields (the MMBatchList tutorial should go into more detail for that). Passing a blank string will disable sort for the column.
          
          
              SetOnRetrieveValue( onretrievevalue )
                  onretrievevalue is actually a function. This can be an anonymous function, or a declared function, but it must follow the format: function( record ) { return record.some_member; }. This is useful in circumstances where the value you want to display differs from the column code. Take the shipment list as an example. The JSON response we get back has the shipment information with the order information as a nested object (ie, record.order.xxx_member instead of record.xxx_member). In that example, our column code might be 'orderdate', but the data is nested in another object, so we would need to have a new retriever function in order to properly get the orderdate from the loaded data: SetOnRetrieveValue( function( record ) { return record.order.orderdate; } ); You can also use this to show/retrieve the data for a given row's column for any value you want. You could even hard code a response if you wanted.
          
          
              SetOnSetValue( onsetvalue )
                  This function is the other end of SetOnRetrieveValue. It too takes a function as a parameter: function( record, value ) { record.some_member = value; }. This allows you to set any member in a record to the value passed in. This is used when in inline edit mode. There are numerous uses for this: updating two fields with the data from one (take a store selector as an example. You want to display the store code or name, but pass the store_id as a parameter, so when you change the store dropdown to another store, your onSetValue function would change both the record.store_id value AND the record.store_code/name value), updating a nested record (ie, instead of record.orderdate, record.order.orderdate), etc.
          
          
              SetWidth( css_width_string )
                  This sets the default/minimum column width. 
          
          
              SetUpdateOnModifiedOnly( true | false )
                  If the list supports inline row editing, you can set a given column to update its data only when the value has changed (instead of every time). This is useful for things like custom fields (as an example of its use in Miva Merchant) so that we update/send the fields ONLY when they are changed to avoid unnecessary update calls. This also prevents using up unnecessary bandwidth. If you have 50 custom fields and you want to change the product code, for instance, you wouldn't want to send the data from 50 custom fields just to save the one code. Instead, you would have that column update its data only when the data is modified from its original value.
          
          
              SetOnParseEditableColumn( onparseeditablecolumn )
                  onParseEditableColumn is the function that parses out the values from inputs, selects, radios, checkboxes, etc when in inline add/edit mode. If your editable column has custom edit mode fields that cannot be parsed by the default onParseEditableColumn function, you will need to use this function and pass in a function( new_record, element_column ) { ; } to handle the custom parsing. I won't go into too much detail with this, because examples can be seen in the LSK, and each case here will be different.
          
          
              SetOnDisplayFieldError(  ondisplayfielderror )
                  Similar in concept to onParseEditableColumn. You can override how errors for your column are displayed (make them have green borders or flashing pink swirly circles)
          
          
              SetOnDisplayData( function( record, item, mmbatchlist ) { return document.createTextNode( record.some_member ); } )
                  This function allows you to display your data in a specific way (custom select fields, divs, adding buttons, etc). You are passed the row's record, the row's item (which contains a whole host of information), and a reference to the mmbatchlist variable (the list). You must ALWAYS return an element.
          
          
              SetOnDisplayEdit( function( record, item, mmbatchlist ) { var input; input = newElement( 'input', { 'type': 'text', 'name': name, 'class': 'mm9_batchlist_data_col_editableinput' }, null, null ); return input; } )
                  Exactly the same as SetOnDisplayData, but for edit mode. You can use this to make custom displayed edit fields or you can make certain columns not editable by outputting the data in a non-editable field.
          
          
              SetOnExportData( function( record ) { return record.some_member; } )
                  This is used for the CSV download functionality. You can have your column export custom data (ie, if your visual data shows you formatted price, you can output the price without the dollar sign)
          
          
              SetSortByText( text )
                  Use this to change the text displayed in the "Sort" dropdown menu for your column
          
          
              SetFieldName( fieldname )
                  This sets the field name that gets passed to the server as the "Name" in the name-value-pair for the edited/added data. Example: column cost would have "Cost" as the fieldname value and when passed to the server you would get g.Cost with a value of whatever your editable field had.
          
          
              SetDefaultActive( true | false )
                  Default is false. If false, the column is not visible by default (you would have to go into the Show/Hide Columns menu and manually show it). If true, it WILL be shown by default.
          Ryan Guisewite
          Lead UI Developer / Miva, Inc.
          www.miva.com

          Comment


            #6
            Re: Miva 9 Bartch Screens (like Categories)

            Thank you Ryan. this is a BIG help.

            Since the new API is JavaScript based, perhaps the files could be included in the next LSK, ( so we don't have to go through the process of search/copy/paste/save/repeat ) along with a documentation file like what you have above as mmbatchlist.txt

            I see over half of mmbatchlist.js is based on MMBatchList_NoFeatures(). I've not yet studied the methods in detail, my question...

            When would I use DeriveFrom( MMBatchList_NoFeatures, my_List ) vs. DeriveFrom( MMBatchList, my_List )?

            One more thing. It seems like once a page is loaded, and I reload the page, after making changes to the Javascript, the changes are not applied. It's as if it's appearance saved somewhere. I don't know if this is due to the browser or something in the Admin. Either way it makes development / debugging a bit of a pain. How do I overcome this?
            Last edited by RayYates; 01-05-16, 06:42 AM.
            Ray Yates
            "If I have seen further, it is by standing on the shoulders of giants."
            --- Sir Isaac Newton

            Comment


              #7
              Re: Miva 9 Bartch Screens (like Categories)

              Originally posted by RayYates View Post
              Thank you Ryan. this is a BIG help.

              Since the new API is JavaScript based, perhaps the files could be included in the next LSK, ( so we don't have to go through the process of search/copy/paste/save/repeat ) along with a documentation file like what you have above as mmbatchlist.txt

              I see over half of mmbatchlist.js is based on MMBatchList_NoFeatures(). I've not yet studied the methods in detail, my question...

              When would I use DeriveFrom( MMBatchList_NoFeatures, my_List ) vs. DeriveFrom( MMBatchList, my_List )?

              One more thing. It seems like once a page is loaded, and I reload the page, after making changes to the Javascript, the changes are not applied. It's as if it's appearance saved somewhere. I don't know if this is due to the browser or something in the Admin. Either way it makes development / debugging a bit of a pain. How do I overcome this?
              Good morning Ray,

              MMBatchList_NoFeatures is the batchlist class that has nothing set up yet (no headers, no action bar with buttons, no searchbar, no column move functionality, no exporting of records, etc). All of the functionality is there in the prototype declarations, but they are not enabled by default. The MMBatchList( parent_id ) class HAS all of that generic functionality that will be used by 99.99% of all classes set up already. If you open the order overlay list (Order Processing > Orders, double click on an order and the resulting popup with the list on the left and the details pane on the right), the list there is an MMBatchList_NoFeatures list (with a few custom modifications). Essentially it is just a list of records with nothing else there.

              So, in answer to your question, you should almost always use the MMBatchList class instead of MMBatchList_NoFeatures when setting up your batchlist.

              In answer to your second question... It is most likely a caching thing. I use Chrome during development and have the developer console open 99% of the time. There is a setting there where you can turn off page caching so that files are fetched/processed every time (and therefore new changes will be shown instead of old cached ones being pulled in). This will only help if it is actually a "javascript being changed" issue. If you're resizing columns manually or showing/hiding columns... that is a saved preference and you must edit your user and go to the Preferences tab and delete that (or all) user preferences. User preferences are only saved when user input changes something, so you changing something in the JS and then clicking refresh, changing something again, clicking refresh... that won't save a preference. However, if you change something, show a column, resize a column, change something else in JS and go back... the shown/resized column will retain the previously saved "preference". I'm not sure which of the two scenarios you're coming across, but it should be easy to diagnose from your end between those two options (clearing the cache or emptying the user preferences)
              Ryan Guisewite
              Lead UI Developer / Miva, Inc.
              www.miva.com

              Comment


                #8
                Re: Miva 9 Bartch Screens (like Categories)

                Thanks Ryan for your help.

                I'm making slow progress on making my Map Locations module use the Merchant 9 API working a few hours bit every night.

                I'm not longer overwhelmed, merely overloaded :)

                Anyway, next question:

                This is part of Gmap_List.prototype.onCreateRootColumnList

                Code:
                new MMBatchList_Column_Text( 'Address 1', 'address1', 'Address1' )    .SetDisplayInList( false )
                    .SetSearchable( false ),
                
                
                new MMBatchList_Column_Text( 'Address 2', 'address2', 'Address2' )
                    .SetDisplayInList( false )
                    .SetSearchable( false ),
                
                
                new MMBatchList_Column_Text( 'City', 'city', 'City' ),
                new MMBatchList_Column_Text( 'State', 'state', 'State' ),
                new MMBatchList_Column_Text( 'Zip', 'postal_code', 'Zip' ),
                new MMBatchList_Column_Text( 'Country', 'country', 'Country' ),
                I do not want the columns address1 and address2 to display on the initial page load but still be available in the "Show/Hide Columns" menu.

                But when I use .SetDisplayInList( false ) it removes it from the list and the menu. So I add SetDisplayInMenu( true )
                Now it displays in the menu, but selecting it does not display the item. What am I doing wrong?
                Last edited by RayYates; 01-12-16, 09:40 AM.
                Ray Yates
                "If I have seen further, it is by standing on the shoulders of giants."
                --- Sir Isaac Newton

                Comment


                  #9
                  Re: Miva 9 Bartch Screens (like Categories)

                  Originally posted by RayYates View Post
                  Thanks Ryan for your help.

                  I'm making slow progress on making my Map Locations module use the Merchant 9 API working a few hours bit every night.

                  I'm not longer overwhelmed, merely overloaded :)

                  Anyway, next question:

                  This is part of Gmap_List.prototype.onCreateRootColumnList

                  Code:
                  new MMBatchList_Column_Text( 'Address 1', 'address1', 'Address1' )    .SetDisplayInList( false )
                      .SetSearchable( false ),
                  
                  
                  new MMBatchList_Column_Text( 'Address 2', 'address2', 'Address2' )
                      .SetDisplayInList( false )
                      .SetSearchable( false ),
                  
                  
                  new MMBatchList_Column_Text( 'City', 'city', 'City' ),
                  new MMBatchList_Column_Text( 'State', 'state', 'State' ),
                  new MMBatchList_Column_Text( 'Zip', 'postal_code', 'Zip' ),
                  new MMBatchList_Column_Text( 'Country', 'country', 'Country' ),
                  I do not want the columns address1 and address2 to display on the initial page load but still be available in the "Show/Hide Columns" menu.

                  But when I use .SetDisplayInList( false ) it removes it from the list and the menu. So I add SetDisplayInMenu( true )
                  Now it displays in the menu, but selecting it does not display the item. What am I doing wrong?

                  You should use .SetDefaultActive( false ) instead of SetDisplayInList( false ). SetDisplayInList( false) will never allow the column to be displayed in the list.
                  Ryan Guisewite
                  Lead UI Developer / Miva, Inc.
                  www.miva.com

                  Comment


                    #10
                    Thanks again Ryan

                    Moving on
                    I have implemented the delete features using:

                    this.Feature_Delete_Enable( 'Delete Location(s)' );and created the functions Gmap_List.prototype.onDelete and Gmap_List.prototype.onDeleteList I have this working so I can delete single or multiple records calling the ajax function Gmap_Delete( location_ids, callback, delegator )

                    Now I have a custom button I want to implement that's has identical functionality except instead of deleting these records will call Googles Map API to perform geo-location.

                    So far I have:

                    this.button_geolocate = this.Feature_Buttons_AddButton_Dynamic_SingleSelec t( 'Geolocate', 'Re Geolocate location(s)', 'here', this.onGeolocate ); and added some of the support functions.

                    I was wondering, Is there a way that I can some how derive my new buttons functionality from Feature_Delete? in the end it would call the ajax function Gmap_Geolocate() but would otherwise function in exactly the same way. Then I would not have to copy all the code out of mmbatchlist.js and make changes.

                    Ray Yates
                    "If I have seen further, it is by standing on the shoulders of giants."
                    --- Sir Isaac Newton

                    Comment


                      #11
                      Originally posted by RayYates View Post
                      Thanks again Ryan

                      Moving on
                      I have implemented the delete features using:

                      this.Feature_Delete_Enable( 'Delete Location(s)' );and created the functions Gmap_List.prototype.onDelete and Gmap_List.prototype.onDeleteList I have this working so I can delete single or multiple records calling the ajax function Gmap_Delete( location_ids, callback, delegator )

                      Now I have a custom button I want to implement that's has identical functionality except instead of deleting these records will call Googles Map API to perform geo-location.

                      So far I have:

                      this.button_geolocate = this.Feature_Buttons_AddButton_Dynamic_SingleSelec t( 'Geolocate', 'Re Geolocate location(s)', 'here', this.onGeolocate ); and added some of the support functions.

                      I was wondering, Is there a way that I can some how derive my new buttons functionality from Feature_Delete? in the end it would call the ajax function Gmap_Geolocate() but would otherwise function in exactly the same way. Then I would not have to copy all the code out of mmbatchlist.js and make changes.

                      Does your list have nested branches/child rows? If not, you can recreate the onDeleteList functionality much easier. onDeleteList is currently longer because by default it must support child rows (for flexibility between all lists). If yours does not, you could easily do something like:

                      Code:
                      Gmap_List.prototype.onGeolocate = function()
                      {
                          var self = this;
                          var i, i_len, item, delegator;
                      
                          if ( this.ActiveItemList_Count() == 0 )
                          {
                              return;
                          }
                      
                          delegator                 = new AJAX_ThreadPool( 3 );
                          delegator.onComplete    = function()
                          {
                              // Do something here. You don't need to, but it is available. This will run once ALL ajax calls have been completed from your list below
                          };
                      
                          for ( i = 0, i_len = this.ActiveItemList_Count(); i < i_len; i++ )
                          {
                              if ( ( item = this.ActiveItemList_ItemAtIndex( i ) ) !== null )
                              {
                                  Gmap_Geolocate( item.record.id, function( response ) { /* Do Something */; }, delegator );
                              }
                          }
                      
                          delegator.Run();
                      }
                      Or, if you wanted to do it as a list of ids...

                      Code:
                      Gmap_List.prototype.onGeolocate = function()
                      {
                          var self = this;
                          var i, i_len, item, id_list, delegator;
                      
                          if ( this.ActiveItemList_Count() == 0 )
                          {
                              return;
                          }
                      
                          delegator                 = new AJAX_ThreadPool( 3 );
                          delegator.onComplete    = function()
                          {
                              // Do something here. You don't need to, but it is available. This will run once ALL ajax calls have been completed from your list below
                          };
                      
                          for ( i = 0, i_len = this.ActiveItemList_Count(); i < i_len; i++ )
                          {
                              if ( ( item = this.ActiveItemList_ItemAtIndex( i ) ) === null )
                              {
                                  continue;
                              }
                      
                              id_list.push( item.record.id );
                      
                              if ( id_list.length >= stoi_max( this.batchlist_count * 5, this.batchlist_max_delete_count ) )
                              {
                                  Gmap_GeolocateList( id_list, function( response ) { /* Do Something */; }, delegator );
                                  id_list = new Array();
                              }
                          }
                      
                          delegator.Run();
                      }
                      If you do have nesting, it will require something closer to the original MMBatchList onDeleteList. Copying the function in JS (without copying all the code) would not work. There are too many things specific to deleting that would throw you off.
                      Ryan Guisewite
                      Lead UI Developer / Miva, Inc.
                      www.miva.com

                      Comment


                        #12
                        I finally got back to this last night. When I select multiple rows the new button disappears. Looking at my code again, I am adding my button with this command.

                        this.button_geolocate = this.Feature_Buttons_AddButton_Dynamic_SingleSelect( 'Geolocate', 'Re Geolocate location(s)', 'here', this.onGeolocate );

                        I could not find a MultiSelect version of this command. Can you point me in the right direction so that I can select single or multiple lines to Geolocate.


                        BTW (for posterity) this code is working. Thank you again.
                        Code:
                        Gmap_List.prototype.onGeolocate = function() {
                            var self = this;
                            var i, i_len, item, delegator;
                            var id_list = new Array();
                        
                            if ( this.ActiveItemList_Count() == 0 )     {
                                return;
                            }
                        
                            delegator = new AJAX_ThreadPool( 3 );
                            delegator.onComplete = function() {
                                self.Refresh();
                            };
                        
                            for ( i = 0, i_len = this.ActiveItemList_Count(); i < i_len; i++ ) {
                                if ( ( item = this.ActiveItemList_ItemAtIndex( i ) ) === null ) {
                                    continue;
                                }
                        
                                id_list.push( item.record.id );
                        
                                if ( id_list.length >= stoi_max( this.batchlist_count * 5, this.batchlist_max_delete_count ) ) {
                                    Gmap_GeolocateList( id_list, function( response ) { /* Do Something */; }, delegator );
                                    id_list = new Array();
                                }
                            }
                        
                            if ( id_list.length > 0 ) {
                                Gmap_GeolocateList( id_list, function( response ) { /* Do Something */; }, delegator );
                            }
                        
                            delegator.Run();
                        }
                        Last edited by RayYates; 01-15-16, 09:49 AM.
                        Ray Yates
                        "If I have seen further, it is by standing on the shoulders of giants."
                        --- Sir Isaac Newton

                        Comment


                          #13
                          Never mind I found .Feature_Buttons_AddButton_Dynamic() This it fantastic, I'm getting rather excited to get this finished up!
                          Ray Yates
                          "If I have seen further, it is by standing on the shoulders of giants."
                          --- Sir Isaac Newton

                          Comment


                            #14
                            The file MMScreen.js contains this function MMScreen.prototype.UpdateMessage_Display = function( message ).
                            It displays a message below the [Update] [Reset] [More] buttons when update is clicked.

                            I would like to call it when I save my module Settings Dialog. H

                            My batchlist.js file contains

                            Code:
                            Gmap_List.prototype.EditSettings = function( ) {
                                var self = this;
                                var gmapsettings;
                            
                                gmapsettings = new Gmap_SettingsDialog( );
                                gmapsettings.onsave    = function() {
                                    UpdateMessage_Display( 'Settings Updated' ); // obviously this does not work
                                }
                                gmapsettings.Show();
                            }
                            How do I make this work?
                            Ray Yates
                            "If I have seen further, it is by standing on the shoulders of giants."
                            --- Sir Isaac Newton

                            Comment


                              #15
                              Code:
                              if ( top.mm9_screen )
                              {
                                  top.mm9_screen.UpdateMessage_Display( 'Settings Updated' );
                              }
                              Ryan Guisewite
                              Lead UI Developer / Miva, Inc.
                              www.miva.com

                              Comment

                              Working...
                              X