Support

Account

Home Forums Add-ons Repeater Field Disable reordering of the repeater field items

Solving

Disable reordering of the repeater field items

  • Hi. Has anybody attempted to disable reordering of the repeater field items? I have a situation where this would be nice to disable. I tried with some script similar to this:
    field.$el[0].sortable(‘disable’);
    I could not get it to work.

  • Could someone help me explain the Javascript API?

    I’ve tried this, but am looking for an action that runs after Sortable is set. “ready_field” runs before.

    acf.addAction('ready_field', function( field ){
        field.$el.addClass('new-way');
    });

    Is there more documentation on Field Actions?

  • Disabling this feature has come up in the past and there is no real solution. Ideas include removing the ACF action or simply hiding the control. You will find this discussion here https://support.advancedcustomfields.com/forums/topic/how-to-disable-dragdrop-ordering-function-on-a-specific-repeaters-field/, I do not know if any of those solutions work.

  • Thanks @hube2 Yes, I have seen that post and have also added my own comment a few days ago. I did not find anything there that works.

  • I can’t give you all of the details, I can just give you some ideas. You will need to add custom JS and you will need to add an action for both the ready and append. The first is used when the page is loaded and the second will be used when a new row is added to the repeater because ACF will automatically add the class to the new row and since the row did not exist during the ready action it will not be removed.

    The following is just an untested example and may need to be corrected.

    In your ready action you will need to find all of the repeater rows and remove the “order” class from the handle, something like this

    
    // the key is for the repeater
    // find all rows of the repeater
    // not that the selector will need to be more specific if you have nested repeater
    // where you don't want to affect the nested repeter
    $('[data-key="field_63597ed1ce1cb"] tr.acf-row').each(function(index, element) {
      // this loops over each repeater row
      // convert the element to a jQuery object
      var target = $(element);
      // remove the "order" class
      target.removeClass('order');
    }
    

    You can do the same thing as above on the append actions, in fact you could set both the ready and append actions to the same function. However, the append action probably passes the element, but I don’t know if this is the repeater element or the row element or something else. I would likely just use the same function.

    Here is an example from a project I worked on a while ago that auto generates unique ID for flexible content so that you can see what you need to do to add the JS to ACF

    
    (function($){
      if (typeof acf == 'undefined') {
        return;
      }
      acf.add_action('ready append', function($el) {
        var panel_ids = [];
        $('[data-key="field_63597ed1ce1cb"] input').each(function(index, element) {
          if (element.value == '' || panel_ids.indexOf(element.value) != -1) {
            var new_id = acf.get_uniqid('pnl-');
            element.value = new_id;
            panel_ids.push(new_id);
          } else {
            panel_ids.push(element.value);
          }
        });
      });
    })(jQuery);
    
  • Hey @hube2 Thanks a lot!! 🙂
    It’s funny because I just found the same solution :-))
    Here is what I got:

    (function($) {
    	
    	jQuery( document ).ready( function( $ ) {
    		
    		if ( typeof acf !== 'undefined' ) {
    			
    			acf.addAction('load_field', function( field ) {
    				if ( field.data.name === 'locations') {
    					
    					const locationsField = field.$el[0];
    					const acfTable = locationsField.querySelector('.acf-table');
    					const acfTableRows = acfTable.querySelectorAll('.acf-table .acf-row');
    					
    					acfTableRows.forEach((row, index) => {
    
    						const handle = row.querySelector('.acf-row-handle');
    						handle.classList.remove('order');
    
    					});
    
    				}
    				
    			});
    
    		}
    	});
    	
    })(jQuery);

    I will have a look at what you did as well…

  • Hello

    I tried another way to prevent sortable feature, in my case on a flexible_content field.
    I started work using this thread, which no more accepts replies.

    
    acf.addAction( <code>ready_field/key=${fieldId.slice( -1 )}</code>, ( field ) => {
      // Prevent sorting
        // TODO was unable to find a way to prevent the sortable feature before starting to drag element
        field.on( 'sortstop', ( e ) => e.preventDefault() )
    
      // Target the right sort handle elements, according to each field type HTML structure
      // Selectors must be precise not to disable sorting in subfield that has to keep its sortable feature
      switch( field.type ) {
        case 'flexible_content':
          // Up to element, then down to handle
          $firstMatching.closest( '.acf-flexible-content' ).find( '> .values > .layout > .acf-fc-layout-handle' )
          .css( 'cursor', 'pointer' )
          .attr( 'title', 'Reorder disabled' )
          break
      }
    } )
    

    This solution abort the sort forcing to keep same order, but not perfect since ACF field is flagged changed so leaving the page prompts to confirm change loss.

    I tried to disable the feature before it begins, for instance using sortstart event with a simple e.preventDefault() but it ends with a JS error.
    I also tried to remove sortor ui-sortable classes. That could work since onHoverSortable() func in wp-content/plugins/advanced-custom-fields-pro/assets/build/js/acf-field-group.js is testing for ui-sortable class to initialize sortable, but a mouseover or mouseenterr event put the class back.

Viewing 7 posts - 1 through 7 (of 7 total)

You must be logged in to reply to this topic.