Magento 2.2 How to show out of stock in configurable product

app/code/Ravindra/Custom/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Ravindra_Custom" setup_version="2.2.2">
    </module>
</config>

app/code/Ravindra/Custom/registration.php

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Ravindra_Custom',
    __DIR__
);

app/code/Ravindra/Custom/etc/di.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">

    <preference for="Magento\Swatches\Block\Product\Renderer\Configurable" type="Ravindra\Custom\Block\Product\View\Type\Configurable" />

    <preference for="Magento\ConfigurableProduct\Model\ConfigurableAttributeData" type="Ravindra\Custom\Model\Rewrite\ConfigurableAttributeData" />
</config>

app/code/Ravindra/Custom/Block/Product/View/Type/Configurable.php

<?php

namespace Ravindra\Custom\Block\Product\View\Type;

use Magento\Catalog\Block\Product\Context;
use Magento\Catalog\Helper\Product as CatalogProduct;
use Magento\ConfigurableProduct\Helper\Data;
use Magento\ConfigurableProduct\Model\ConfigurableAttributeData;
use Magento\Customer\Helper\Session\CurrentCustomer;
use Magento\Framework\Json\EncoderInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Catalog\Model\Product;
use Magento\Framework\Stdlib\ArrayUtils;
use Magento\Store\Model\ScopeInterface;
use Magento\Swatches\Helper\Data as SwatchData;
use Magento\Swatches\Helper\Media;
use Magento\Swatches\Model\Swatch;

class Configurable extends \Magento\Swatches\Block\Product\Renderer\Configurable 
{

     public function __construct(
        Context $context,
        ArrayUtils $arrayUtils,
        EncoderInterface $jsonEncoder,
        Data $helper,
        CatalogProduct $catalogProduct,
        CurrentCustomer $currentCustomer,
        PriceCurrencyInterface $priceCurrency,
        ConfigurableAttributeData $configurableAttributeData,
        SwatchData $swatchHelper,
        Media $swatchMediaHelper,
        array $data = []
    ){
         $this->swatchHelper = $swatchHelper;
        $this->swatchMediaHelper = $swatchMediaHelper;
         parent::__construct(
            $context,
            $arrayUtils,
            $jsonEncoder,
            $helper,
            $catalogProduct,
            $currentCustomer,
            $priceCurrency,
            $configurableAttributeData,
            $swatchHelper,
            $swatchMediaHelper,
            $data
        );
    }

    public function getJsonConfig() {
        $store = $this->getCurrentStore();
        $currentProduct = $this->getProduct();

        $regularPrice = $currentProduct->getPriceInfo()->getPrice('regular_price');
        $finalPrice = $currentProduct->getPriceInfo()->getPrice('final_price');

        $options = $this->helper->getOptions($currentProduct, $this->getAllowProducts());
        $attributesData = $this->configurableAttributeData->getAttributesData($currentProduct, $options);

        $config = [
            'attributes' => $attributesData['attributes'],
            'template' => str_replace('%s', '<%- data.price %>', $store->getCurrentCurrency()->getOutputFormat()),
            'optionPrices' => $this->getOptionPrices(),
            'optionStock' => $this->getOptionStocks(),
            'prices' => [
                'oldPrice' => [
                    'amount' => $this->_registerJsPrice($regularPrice->getAmount()->getValue()),
                ],
                'basePrice' => [
                    'amount' => $this->_registerJsPrice(
                        $finalPrice->getAmount()->getBaseAmount()
                    ),
                ],
                'finalPrice' => [
                    'amount' => $this->_registerJsPrice($finalPrice->getAmount()->getValue()),

                ],
            ],

            'productId' => $currentProduct->getId(),
            'chooseText' => __('Choose an Option...'),
            'images' => isset($options['images']) ? $options['images'] : [],
            'index' => isset($options['index']) ? $options['index'] : [],
        ];

        if ($currentProduct->hasPreconfiguredValues() && !empty($attributesData['defaultValues'])) {
            $config['defaultValues'] = $attributesData['defaultValues'];
        }

        $config = array_merge($config, $this->_getAdditionalConfig());

        return $this->jsonEncoder->encode($config);
    }


    /*-----------------------custom code----------------------*/

    protected function getOptionStocks() {
        $stocks = [];
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();       
        $stockObject=$objectManager->get('Magento\CatalogInventory\Api\StockRegistryInterface');

        foreach ($this->getAllowProducts() as $product) {          
            $productStockObj = $stockObject->getStockItem($product->getId());
            $isInStock = $productStockObj['is_in_stock'];
            $stocks[$product->getId()] = ['stockStatus' => $isInStock];
        }
        return $stocks;
    }

}

app/code/Ravindra/Custom/Block/ConfigurableProduct.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Ravindra\Custom\Block;

use Magento\Framework\View\Element\Template;

class ConfigurableProduct extends Template
{   
    protected $_storeManager;

    public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    array $data = []
    ){ 
        parent::__construct($context, $data);
        $this->_storeManager = $context->getStoreManager();
    }

}

app/code/Ravindra/Custom/Model/Rewrite/ConfigurableAttributeData.php

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Ravindra\Custom\Model\Rewrite;

use Magento\Catalog\Model\Product;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;

class ConfigurableAttributeData extends \Magento\ConfigurableProduct\Model\ConfigurableAttributeData
{

    protected $eavConfig;

    public function __construct(\Magento\Eav\Model\Config $eavConfig) {
        $this->eavConfig = $eavConfig;
    }

    public function getAttributeOptionsData($attribute, $config) {
        $attributeOptionsData = [];

        $attributeId = $attribute->getAttributeId();

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $eavModel = $objectManager->create('Magento\Catalog\Model\ResourceModel\Eav\Attribute');
        $attr = $eavModel->load($attributeId);
        $attributeCode=$eavModel->getAttributeCode();


        $attribute = $this->eavConfig->getAttribute('catalog_product', $attributeCode);
        $options = $attribute->getSource()->getAllOptions();


        foreach ($options as $attributeOption) {
            $optionId = $attributeOption['value'];
            $attributeOptionsData[] = [
                'id' => $optionId,
                'label' => $attributeOption['label'],
                'products' => isset($config[$attribute->getAttributeId()][$optionId])
                    ? $config[$attribute->getAttributeId()][$optionId]
                    : [],
            ];
        }
        return $attributeOptionsData;
    }

}

app/code/Ravindra/Custom/view/frontend/layout/catalog_product_view.xml

<?xml version="1.0"?>

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <head>        
        <css src="Ravindra_Custom::css/configurableproduct.css"/>
    </head>    
</page>

app/code/Ravindra/Custom/view/frontend/layout/catalog_product_view_type_configurable.xml

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
       <referenceBlock name="product.info.configurable">
            <action method='setTemplate'>
                <argument name="template" xsi:type="string">Ravindra_Custom::configurable-available.phtml</argument>
            </action>           
        </referenceBlock>       
    </body>
</page>

app/code/Ravindra/Custom/view/frontend/templates/configurable-available.phtml

   <?php /* @var $block \Magento\Catalog\Block\Product\View\AbstractView */?>
<?php $_product = $block->getProduct() ?>
<?php $stockblock =  $this->getLayout()->createBlock('Ravindra\Custom\Block\ConfigurableProduct'); ?>

<?php if ($block->displayProductStockStatus()): ?>
    <?php if ($_product->isAvailable()): ?>
        <div class="stock available mcs-available" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('In stock') ?></span>
        </div>
    <?php else: ?>
        <div class="stock unavailable" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span>
        </div>

        <div class="ravi-stockalert">   
                <div class="rav-subscriber-title"><?php
                /* @escapeNotVerified */ 


                ?>
                </div>
                <div class="ravi-stockalert-form">      
                    <form name="stockalert_form" id="stockalert_form" method="POST" action="<?php echo $stockblock->getStockalertPostUrl(); ?>" data-mage-init='{"validation":{}}'>
                        <div class="email-stockalert-input">
                            <input class="input-text" type="email" data-validate="{required:true, 'validate-email':true}" type="text" placeholder="Enter email address" name="email" />
                        </div>
                        <input type="hidden" id="cp_product_id" name="product_id" value="<?php echo $_product->getId(); ?>" >
                        <input type="hidden" name="product_name" value="<?php echo $_product->getName(); ?>" >
                        <div class="submit-stockalert-input">
                            <input type="submit" class="stockalert-submit-btn" name="submit" value="subscribe">
                        </div>
                    </form>
                    <div style="clear:both;"></div>
                </div>
            </div>

    <?php endif; ?>

    <div class="mcs-config-product-stockalert" id="mcs-config-product-stockalert" style="display:none;">
        <div class="stock unavailable" title="<?php /* @escapeNotVerified */ echo __('UnAvailability') ?>">
            <span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span>
        </div>
    </div>

<?php endif; ?>

app/code/Ravindra/Custom/view/frontend/web/css/configurableproduct.css

.email-stockalert-input{
    float:left;
    width: 80%;
}
.submit-stockalert-input {
    width: 20%;
    float: right;
}
.email-stockalert-input input, .submit-stockalert-input input{
    height: 40px;
}
.submit-stockalert-input input{
    float: left;
    width: 100%;
    background: #1979c3;
    border: 1px solid #1979c3;
    color: #ffffff;
    cursor: pointer;
    display: inline-block;
    font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
    font-weight: 600;
    font-size: 14px;
    text-transform: capitalize;
}
.stockalert-submit-btn:hover{
    background: #333;
    border: 1px solid #333;
}
.ravi-stockalert, .ravi-stockalert-bundle, .ravi-stockalert-group{
    /*text-align: center !important;*/
    margin: 10px 0px;
    border: 1px #ccc solid;
    padding: 10px;
}
.product-info-stock-sku{
    display:block !important;
}
.product-info-price{
    /*width: 55% !important;*/
}
.product-info-main .product-info-price .price-box{
    width: 100%;
    float: left;
}
.product-info-main .product-info-stock-sku{
    float: left;
    min-width: 100%;
    padding-left: 0px;
}
.stock.unavailable{
    text-align:left;
    color:#F00;
    font-size: 16px;
    font-weight: 400 !important;
}
.sku .value, .sku{
    text-align:left;
}
.ravi-stockalert-form {
    margin: 5px 0;
    width: 100%;

}

.page-product-grouped .product-info-price{
    width:100%;
}
.table.grouped .col.item {
   width: 13%;
}
.grouped .email-stockalert-input{
    width: 69%;
}
.grouped .submit-stockalert-input{
    width: 31%
}
.grouped .submit-stockalert-input input{
    font-size: 12px;
}
.grouped .table.grouped .col.qty{
    padding: 11px 0px;
}
.item span, .item strong{
    color: #1979C3;
}
.grouped .product-item-name {
    color: #000 !important;
    font-size: 16px;
}
.rav-subscriber-title {
    text-align: left;
}
.guest_users_message{
    text-align:left;
}

app/code/Ravindra/Custom/view/frontend/requirejs-config.js

var config = {
    map: {
        '*': {

            'Magento_Swatches/js/swatch-renderer':'Ravindra_Custom/js/swatch-renderer', 
            configurable:'Ravindra_Custom/js/configurable',

        }
    }
};