Magento 2.1 – Fix Checkout Shipping Address Dropdown Issue

checkoutmagento-2.1onepage-checkoutshipping-address

Magento 2 Shipping address selection changes to drop down form radio options. I want to display default shipping address on page load but it's always showing first shipping address as a selected. In Magento_Checkout/template/shipping-address/list.html :

<div class="field addresses">
    <div class="control">
        <div class="shipping-address-items">
            <select class="select" name="billing_address_id" data-bind="
        options: shippingAddressOptions,
        optionsText: shippingAddressOptionsText,
        value: selectedShippingAddress,
        selectedOptions: chosenCountries,
        event: {change: onShippingAddressChange(selectedShippingAddress())};
    "></select>
        </div>
    </div>
</div>

In js/view/shipping.js file:

define(
[
    'jquery',
    "underscore",
    'Magento_Ui/js/form/form',
    'ko',
    'Magento_Customer/js/model/customer',
    'Magento_Customer/js/model/address-list',
    'Magento_Checkout/js/model/address-converter',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/create-shipping-address',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Checkout/js/model/shipping-rates-validator',
    'Magento_Checkout/js/model/shipping-address/form-popup-state',
    'Magento_Checkout/js/model/shipping-service',
    'Magento_Checkout/js/action/select-shipping-method',
    'Magento_Checkout/js/model/shipping-rate-registry',
    'Magento_Checkout/js/action/set-shipping-information',
    'Magento_Checkout/js/model/step-navigator',
    'Magento_Ui/js/modal/modal',
    'Magento_Checkout/js/model/checkout-data-resolver',
    'Magento_Checkout/js/checkout-data',
    'uiRegistry',
    'Magento_Catalog/js/price-utils',
    'mage/translate',        
    'Magento_Checkout/js/model/shipping-rate-service'
],
function(
    $,
    _,
    Component,
    ko,
    customer,
    addressList,
    addressConverter,
    quote,
    createShippingAddress,
    selectShippingAddress,
    shippingRatesValidator,
    formPopUpState,
    shippingService,
    selectShippingMethodAction,
    rateRegistry,
    setShippingInformationAction,
    stepNavigator,
    modal,
    checkoutDataResolver,
    checkoutData,
    registry,
    priceUtils,
    $t
) {
    'use strict';
    var popUp = null,
    shippingAddress = quote.shippingAddress,
    newAddressOption = {
            getAddressInline: function () {
            return $t('New Address');
        },
            customerAddressId: null
        },
        shippingAddressOptions = addressList().filter(function (address) {
            return address.getType() == 'customer-address';
        });

    shippingAddressOptions.push(newAddressOption);
    return Component.extend(
        {
            defaults: {
                template: 'Magento_Checkout/shipping'
            },
            visible: ko.observable(!quote.isVirtual()),
            errorValidationMessage: ko.observable(false),
            isCustomerLoggedIn: customer.isLoggedIn,
            isFormPopUpVisible: formPopUpState.isVisible,
            isFormInline: addressList().length == 0,
            isNewAddressAdded: ko.observable(false),
            saveInAddressBook: 1,
            quoteIsVirtual: quote.isVirtual(),
            shippingAddressOptions: shippingAddressOptions,
            chosenCountries:ko.observableArray([shippingAddress]),

Best Answer

I have to change data-bind funtion to

optionsAfterRender: function(option, item) { if(){ selectedShippingAddress(item); } }

keep your backup file before any changes. Complete solutions: It worked for my requirement. You may do some change according to your requirement. But using this we can change shipping address list to drop down.

Add custom address template name : Magento_Checkout/shipping-address/mylist.html

<!-- ko if: (visible)-->
<div class="field addresses">
<div class="control">
    <div class="shipping-address-items">
        <select class="select" name="billing_address_id" data-bind="
    options: shippingAddressOptions,
    optionsText: shippingAddressOptionsText,
    value: selectedShippingAddress,
    optionsAfterRender: function(option, item) {
    if(item.customerAddressId==Object.entries(quoteShippingAddress)[2][1].customerAddressId) {
    selectedShippingAddress(item);
     }
    },
    event: {change: onShippingAddressChange(selectedShippingAddress())};
"></select>
    </div>
</div>

Change and add mylist.html file in shipping.html file.

    <!-- ko if: (!quoteIsVirtual) -->
        <!-- ko foreach: getRegion('customer-email') -->
            <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    <!--/ko-->

   <!-- ko foreach: getRegion('before-form') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!--/ko-->


    <!-- Address form pop up -->

        <div id="opc-new-shipping-address" data-bind="visible: isShippingAddressFormVisible()">
       <!-- ko template: 'Magento_Checkout/shipping-address/form' --><!-- /ko -->
    </div>
        <div class="actions-toolbar">
        <div class="primary">
            <button class="action action-update" type="button" data-bind="click: updateShippingAddress">
                <span data-bind="i18n: 'Update'"></span>
            </button>
            <!-- <button class="action action-cancel" type="button" data-bind="click: cancelAddressEdit"> 
             <span data-bind="i18n: 'Cancel'"></span>
            </button> -->
        </div>
        </div>
   </div>
 </li>
 <!-- Shipping method template -->
 <li id="opc-shipping_method"
class="checkout-shipping-method"
data-bind="fadeVisible: visible(), blockLoader: isLoading"
role="presentation">
<div class="checkout-shipping-method">
    <div class="step-title" data-bind="i18n: 'Shipping Method'" data-role="title"></div>
    <!-- ko foreach: getRegion('before-shipping-method-form') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!-- /ko -->
    <div id="checkout-step-shipping_method"
         class="step-content"
         data-role="content"
         role="tabpanel"
         aria-hidden="false">
        <!-- ko if: rates().length  -->
        <form class="form methods-shipping" id="co-shipping-method-form" data-bind="submit: setShippingInformation" novalidate="novalidate">
            <div id="checkout-shipping-method-load">
                  <table class="table-checkout-shipping-method">
                    <thead>
                        <tr class="row">
                            <th class="col col-method" data-bind="i18n: 'Select Method'"></th>
                            <th class="col col-method" data-bind="i18n: 'Method Title'"></th>
                            <th class="col col-price" data-bind="i18n: 'Price'"></th>                                
                 <!-- <th class="col col-carrier" data-bind="i18n: 'Carrier Title'"></th> -->
                        </tr>
                    </thead>
                    <tbody>

                    <!-- ko foreach: { data: rates(), as: 'method'}-->
                    <tr class="row" data-bind="click: $parent.selectShippingMethod">
                        <td class="col col-method">
                            <!-- ko ifnot: method.error_message -->
                            <!-- ko if: $parent.rates().length == 1 -->
                  <input class="radio"
                                   type="radio"
                                   data-bind="attr: {
                                                checked: $parent.rates().length == 1,
                                                'value' : method.carrier_code + '_' + method.method_code,
                                                'id': 's_method_' + method.method_code,
                                                'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                             }" />
                            <!-- /ko -->
                            <!--ko ifnot: ($parent.rates().length == 1)-->
                            <input type="radio"
                                   data-bind="
                                            value: method.carrier_code + '_' + method.method_code,
                                            checked: $parent.isSelected,
                                            attr: {
                                                'id': 's_method_' + method.carrier_code + '_' + method.method_code,
                                                'aria-labelledby': 'label_method_' + method.method_code + '_' + method.carrier_code + ' ' + 'label_carrier_' + method.method_code + '_' + method.carrier_code
                                            },
                                            click: $parent.selectShippingMethod"
                                   class="radio"/>
                            <!--/ko-->
                            <!-- /ko -->
                        </td>

                        <td class="col col-method"
                                data-bind="text: method.method_title, attr: {'id': 'label_method_' + method.method_code + '_' + method.carrier_code}"></td>   


                        <!-- <td class="col col-carrier"
                                data-bind="text: method.carrier_title, attr: {'id': 'label_carrier_' + method.method_code + '_' + method.carrier_code}"></td> -->

                        <td class="col col-price">
                            <!-- ko foreach: $parent.getRegion('price') -->
                            <!-- ko template: getTemplate() --><!-- /ko -->
                            <!-- /ko -->
                        </td>         


                    </tr>

                    <!-- ko if:  method.error_message -->
                    <tr class="row row-error">
                        <td class="col col-error" colspan="4">
                            <div class="message error">
                                <div data-bind="text: method.error_message"></div>
                            </div>
                            <span class="no-display">
                                <input type="radio" data-bind="attr: {'value' : method.method_code, 'id': 's_method_' + method.method_code}"/>
                            </span>
                        </td>
                    </tr>
                    <!-- /ko -->

                    <!-- /ko -->
                    </tbody>
                </table>
            </div>
            <div id="onepage-checkout-shipping-method-additional-load">
                <!-- ko foreach: getRegion('shippingAdditional') -->
                <!-- ko template: getTemplate() --><!-- /ko -->
                <!-- /ko -->
            </div>
            <!-- ko if: errorValidationMessage().length > 0 -->
            <div class="message notice">
                <span><!-- ko text: errorValidationMessage()--><!-- /ko --></span>
            </div>
            <!-- /ko -->
           <!-- <div class="actions-toolbar" id="shipping-method-buttons-container">
                <div class="primary">
        <button data-role="opc-continue" type="submit" class="button action continue primary">-->
        <!--<span>&lt;!&ndash; ko i18n: 'Next'&ndash;&gt;&lt;!&ndash; /ko &ndash;&gt;</span>-->
                 <!--   </button>
                </div>
            </div> -->
        </form>
        <!-- /ko -->
        <!-- ko ifnot: rates().length > 0 --><div class="no-quotes-block"><!-- ko i18n: 'Sorry, no quotes are available for this order at this time'--><!-- /ko --></div><!-- /ko -->
    </div>
</div>

Now add Shipping.js file.

 define(
[
    'jquery',
    "underscore",
    'Magento_Ui/js/form/form',
    'ko',
    'Magento_Customer/js/model/customer',
    'Magento_Customer/js/model/address-list',
    'Magento_Checkout/js/model/address-converter',
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/action/create-shipping-address',
    'Magento_Checkout/js/action/select-shipping-address',
    'Magento_Checkout/js/model/shipping-rates-validator',
    'Magento_Checkout/js/model/shipping-address/form-popup-state',
    'Magento_Checkout/js/model/shipping-service',
    'Magento_Checkout/js/action/select-shipping-method',
    'Magento_Checkout/js/model/shipping-rate-registry',
    'Magento_Checkout/js/action/set-shipping-information',
    'Magento_Checkout/js/model/step-navigator',
    'Magento_Ui/js/modal/modal',
    'Magento_Checkout/js/model/checkout-data-resolver',
    'Magento_Checkout/js/checkout-data',
    'uiRegistry',
    'Magento_Catalog/js/price-utils',
    'mage/translate',
    'Magento_Checkout/js/model/shipping-rate-service'
],
function(
    $,
    _,
    Component,
    ko,
    customer,
    addressList,
    addressConverter,
    quote,
    createShippingAddress,
    selectShippingAddress,
    shippingRatesValidator,
    formPopUpState,
    shippingService,
    selectShippingMethodAction,
    rateRegistry,
    setShippingInformationAction,
    stepNavigator,
    modal,
    checkoutDataResolver,
    checkoutData,
    registry,
    priceUtils,
    $t
) {
    'use strict';
    var popUp = null,
    newAddressOption = {
            getAddressInline: function () {
            return $t('New Address');
        },
            customerAddressId: null
        },
        shippingAddressOptions = addressList().filter(function (address) {
            return address.getType() == 'customer-address';
        });

    shippingAddressOptions.push(newAddressOption);
    return Component.extend(
        {
            defaults: {
                template: 'Magento_Checkout/shipping'
            },
            visible: ko.observable(!quote.isVirtual()),
            errorValidationMessage: ko.observable(false),
            isCustomerLoggedIn: customer.isLoggedIn,
            isFormPopUpVisible: formPopUpState.isVisible,
            isFormInline: addressList().length == 0,
            isNewAddressAdded: ko.observable(false),
            saveInAddressBook: 1,
            quoteIsVirtual: quote.isVirtual(),
            shippingAddressOptions: shippingAddressOptions,
            initialize: function () {
                var self = this;
                this._super()
                .observe({
                    selectedShippingAddress: null,
                    isShippingAddressFormVisible: !customer.isLoggedIn() || shippingAddressOptions.length == 1
                });
                 if (!quote.isVirtual()) {
                     stepNavigator.registerStep(
                         'payment',
                         '',
                         'Review & Payments',
                         this.visible, _.bind(this.navigate, this),
                         10
                     );
                 }

                checkoutDataResolver.resolveShippingAddress();

                var hasNewAddress = addressList.some(
                    function (address) {
                        return address.getType() == 'new-customer-address';
                    }
                );

                this.isNewAddressAdded(hasNewAddress);

                this.isFormPopUpVisible.subscribe(
                    function (value) {
                        if (value) {
                            self.getPopUp().openModal();
                        }
                    }
                );

                quote.shippingMethod.subscribe(
                    function (value) {
                        self.errorValidationMessage(false);
                    }
                );

                registry.async('checkoutProvider')(function (checkoutProvider) {
                    var shippingAddressData = checkoutData.getShippingAddressFromData();
                    if (shippingAddressData) {
                        checkoutProvider.set(
                            'shippingAddress',
                            $.extend({}, checkoutProvider.get('shippingAddress'), shippingAddressData)
                        );
                    }
                    checkoutProvider.on(
                        'shippingAddress', function (shippingAddressData) {
                            checkoutData.setShippingAddressFromData(shippingAddressData);
                        }
                    );
                });

                this.rates.subscribe(
                    function (grates) {
                        self.shippingRateGroups([]);
                        _.each(
                            grates, function (rate) {
                                var carrierTitle = rate['carrier_title'];

                                if (self.shippingRateGroups.indexOf(carrierTitle) === -1) {
                                    self.shippingRateGroups.push(carrierTitle);
                                }
                            }
                        );
                    }
                );

                return this;
            },

            navigate: function () {
                //load data from server for shipping step
            },

            shippingAddressOptionsText: function (address) {
            return address.getAddressInline();
            },
            onShippingAddressChange: function (address) {
                this.isShippingAddressFormVisible(address == newAddressOption);
            },
            updateShippingAddress: function () {
            if (this.selectedShippingAddress() && this.selectedShippingAddress() != newAddressOption) {
                selectShippingAddress(this.selectedShippingAddress());
                checkoutData.setSelectedShippingAddress(this.selectedShippingAddress().getKey());
              //  this.isShippingMethodFormVisible(true);
            } else {
              this.source.set('params.invalid', false);
                this.source.trigger('shippingAddress.data.validate');

                if (!this.source.get('params.invalid')) {
                    var addressData = this.source.get('shippingAddress');
                  // if user clicked the checkbox, its value is true or false. Need to convert.
                    addressData.save_in_address_book = this.saveInAddressBook ? 1 : 0;

                    // New address must be selected as a shipping address
                    var newShippingAddress = createShippingAddress(addressData);
                    selectShippingAddress(newShippingAddress);
                    checkoutData.setSelectedShippingAddress(newShippingAddress.getKey());
                    checkoutData.setNewCustomerShippingAddress(addressData);
                    //this.isShippingMethodFormVisible(true);
                    }
                }
            },

            initElement: function(element) {
                if (element.index === 'shipping-address-fieldset') {
                    shippingRatesValidator.bindChangeHandlers(element.elems(), false);
                }
            },

            getPopUp: function() {
                var self = this;
                if (!popUp) {
                    var buttons = this.popUpForm.options.buttons;
                    this.popUpForm.options.buttons = [
                    {
                        text: buttons.save.text ? buttons.save.text : $t('Save Address'),
                        class: buttons.save.class ? buttons.save.class : 'action primary action-save-address',
                        click: self.saveNewAddress.bind(self)
                    },
                    {
                        text: buttons.cancel.text ? buttons.cancel.text: $t('Cancel'),
                        class: buttons.cancel.class ? buttons.cancel.class : 'action secondary action-hide-popup',
                        click: function() {
                            this.closeModal();
                        }
                    }
                    ];
                    this.popUpForm.options.closed = function() {
                        self.isFormPopUpVisible(false);
                    };
                    popUp = modal(this.popUpForm.options, $(this.popUpForm.element));
                }
                return popUp;
            },

            /**
        * Show address form popup
        */
            showFormPopUp: function() {
                this.isFormPopUpVisible(true);
            },


            /**
        * Save new shipping address
        */
            saveNewAddress: function() {
                this.source.set('params.invalid', false);
                this.source.trigger('shippingAddress.data.validate');

                if (!this.source.get('params.invalid')) {
                    var addressData = this.source.get('shippingAddress');
         // if user clicked the checkbox, its value is true or false. Need to convert.
                    addressData.save_in_address_book = this.saveInAddressBook ? 1 : 0;

                    // New address must be selected as a shipping address
                    var newShippingAddress = createShippingAddress(addressData);
                    selectShippingAddress(newShippingAddress);
                    checkoutData.setSelectedShippingAddress(newShippingAddress.getKey());
                    checkoutData.setNewCustomerShippingAddress(addressData);
                    this.getPopUp().closeModal();
                    this.isNewAddressAdded(true);
                }
            },

            /**
        * Shipping Method View
        **/
            rates: shippingService.getShippingRates(),
            shippingRateGroups: ko.observableArray([]),
            isLoading: shippingService.isLoading,
            isSelected: ko.computed(
                function () {

                    return quote.shippingMethod() ? quote.shippingMethod().carrier_code + '_' + quote.shippingMethod().method_code : null;
                }
            ),

            getFormattedPrice: function (price) {
                return priceUtils.formatPrice(price, quote.getPriceFormat());
            },

            getRatesForGroup: function (shippingRateGroupTitle) {
                return _.filter(
                    this.rates(), function (rate) {
                        return shippingRateGroupTitle === rate['carrier_title'];
                    }
                );
            },

            selectShippingMethod: function(shippingMethod) {
                selectShippingMethodAction(shippingMethod);
                checkoutData.setSelectedShippingRate(shippingMethod.carrier_code + '_' + shippingMethod.method_code);
                $('#co-shipping-method-form').submit();
                return true;
            },

            selectVirtualMethod: function(shippingMethod) {
                var flagg = true;
                var METHOD_SEPARATOR = ':';
                var SEPARATOR = '~';
                var rates = new Array();
                var sortedrate = new Array();
                jQuery('.vendor-rates').each(
                    function(indx,elm){
                        var flag = false;
                        jQuery(elm).find('.radio').each(
                            function(i,inpt){
                                if(inpt.checked) {
                                    flag = true;
                                    rates.push(inpt.value);
                                }
                            }
                        );
                        if(!flag) {
                            flagg = false;
                        }
                    }
                );
                if(flagg) {
                    for(var i = 0; i < rates.length; i ++){
                        var sortedValue = rates[i].split(SEPARATOR);
                        var pos = isNaN(parseInt(sortedValue[1])) ? 0 : parseInt(sortedValue[1]);
                        sortedrate[pos] = rates[i];
                    }
                    var rate = '';
                    for(var i=0;i< sortedrate.length;i++){
                        if(sortedrate[i]!=undefined) {
                            if(rate) {
                                rate = rate + METHOD_SEPARATOR + sortedrate[i];
                            }else{
                                rate =  sortedrate[i];
                            }
                        }
                    }
                    if(document.getElementById('s_method_vendor_rates_'+rate)) {
                        var event = new Event('click');
                        document.getElementById('s_method_vendor_rates_'+rate).dispatchEvent(event);
                    }
                }
                return true;
            },

            setShippingInformation: function () {
                if (this.validateShippingInformation()) {
                    setShippingInformationAction().done(
                        function() {
                           // stepNavigator.next();
                        }
                    );
                }
            },

            validateShippingInformation: function () {
                var shippingAddress,
                addressData,
                loginFormSelector = 'form[data-role=email-with-possible-login]',
                emailValidationResult = customer.isLoggedIn();

                if (!quote.shippingMethod()) {
                    this.errorValidationMessage('Please specify a shipping method.');
                    return false;
                }

                if (!customer.isLoggedIn()) {
                    $(loginFormSelector).validation();
                    emailValidationResult = Boolean($(loginFormSelector + ' input[name=username]').valid());
                }

                if (!emailValidationResult) {
                    $(loginFormSelector + ' input[name=username]').focus();
                }

                if (this.isFormInline) {
                    this.source.set('params.invalid', false);
                    this.source.trigger('shippingAddress.data.validate');
                    if (this.source.get('shippingAddress.custom_attributes')) {
                        this.source.trigger('shippingAddress.custom_attributes.data.validate');
                    };
                    if (this.source.get('params.invalid')
                        || !quote.shippingMethod().method_code
                        || !quote.shippingMethod().carrier_code
                        || !emailValidationResult
                    ) {
                        return false;
                    }
                    shippingAddress = quote.shippingAddress();
                    addressData = addressConverter.formAddressDataToQuoteAddress(
                        this.source.get('shippingAddress')
                    );

                    //Copy form data to quote shipping address object
                    for (var field in addressData) {
                        if (addressData.hasOwnProperty(field)
                            && shippingAddress.hasOwnProperty(field)
                            && typeof addressData[field] != 'function'
                        ) {
                            shippingAddress[field] = addressData[field];
                        }
                    }

                    if (customer.isLoggedIn()) {
                        shippingAddress.save_in_address_book = 1;
                    }
                    selectShippingAddress(shippingAddress);
                }
                return true;
            }
        }
    );
}
);