Magento 2, Magento Development, Customization, Extension Development and Integration, Optimization, SEO and Responsive Design

Magento 2, Magento Development, Customization, Extension Development and Integration, Optimization, SEO and Responsive Design

Product Custom Option Swatches For Magento 2

Product Custom Option Swatches For Magento 2, Product Option Swatches + Magento 2, Magento 2 : How to display swatches, custom option swatches, drop-down option swatches, How to Get Product Custom Option In Product Listing Page in Magento 2, color swatches for magento 2, swatches in magento2, m2
3 years back i have created a module Product Custom Option (Pro) with Option Swatches to display product custom option swatches instead of dropdown. Now i have created almost same module for Magento 2.

Using my new module you can display option swatches on product details page by replacing drop-down custom options.


Magento2


After installing this module, you will find new tab in your store configuration section. From here you can add option setting.



Run following command after installing module file in your magento.

php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy
php bin/magento cache:clean
php bin/magento cache:flush



Download

Please post your comment if you have any issue.

Add custom class to body depending on a component - Angular

Sometimes the app that is being developed requires different classes on body of html document for styling each route or page. This can be achieved in Angular 2, Angular 4 and above using the following snippet.


Home Component
...//other code above
export class HomeComponent implements OnInit, OnDestroy {
 ngOnInit(){
    const body = document.getElementsByTagName('body')[0];
    body.classList.add('page-home');
  }

  ngOnDestroy(){
    const body = document.getElementsByTagName('body')[0];
    body.classList.remove('page-home');
  }
...//other code below

Dashboard Component
...//other code above
export class DashboardComponent implements OnInit, OnDestroy {
 ngOnInit(){
    const body = document.getElementsByTagName('body')[0];
    body.classList.add('page-dashboard');
  }

  ngOnDestroy(){
    const body = document.getElementsByTagName('body')[0];
    body.classList.remove('page-dashboard');
  }
...//other code below


AngularJS First Basic Demo For Beginners

In this demo we are going to use a simple text box, label and one button. This demo is for beginners.



I am going to do following things in this demo.

  • Add a Input field which updates a 'username'
  • Output the username property via String Interpolation
  • Add a button which may only be clicked if the username is NOT an empty string
  • Upon clicking the button, the username should be reset to an empty string

Here is the html code

<input 
  type="text" 
  class="form-control" 
  (input)="updateUserName($event)"
  [(ngModel)]="uName"
/>

<p>User Name is: {{ userName }}</p>

<button class="btn btn-primary"
[disabled]='!allowReset'
(click)="resetUserName()">Reset</button>

And here is the TypeScript file code

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-assignment',
  templateUrl: './assignment.component.html',
  styleUrls: ['./assignment.component.css']
})
export class AssignmentComponent implements OnInit {
  allowReset = false;
  userName = "";
  uName = "";

  constructor() { }

  ngOnInit() {
  }

  updateUserName(event: Event){
    this.userName = (<HTMLInputElement>event.target).value;
    this.allowReset = true;

    if(this.userName == ""){
      this.allowReset = false;
    }
  }

  resetUserName(){
    this.userName = "";
    this.uName = "";
    this.allowReset = false;
  }

}

Generate XML Language File For Android Using PHP



This is a common headache for all android users to create xml file for multi languages app. Today i am sharing a simple PHP script that will generate xml language file for android app.

To use this script you need to add all your keywords in a csv file like following image.


Now create one php file, android.php and add following code
<?php

$filename = "multi-language-android-en.csv";
$outputfileName = str_replace(".csv",".xml",$filename);
$file = fopen($filename, 'r');

$xml_file = $outputfileName;
if (file_exists($xml_file)) {
    unlink($xml_file);
}

//$xml_file = "language.xml";
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$productsX = $doc->createElement("resources");
$doc->appendChild($productsX);

while (($line = fgetcsv($file)) !== FALSE) {
    //$line is an array of the csv elements
    //print_r($line);

    if (count($line) > 0) {

        $checktoskip = substr(trim($line[0]), 0, 2);

        if (trim($line[0]) == "" || $checktoskip == "//") {
            $lan_xml = $doc->createComment('Revised April 2008');
        }

        $lan_xml = $doc->createElement("string");

        if (isset($line[0])) {
            $lan_xml->setAttribute('name', trim($line[0]));
        }

        if (isset($line[1])) {
            $name = $doc->createTextNode(trim($line[1]));
        }

        $lan_xml->appendChild($name);

        $productsX->appendChild($lan_xml);
    }
}

file_put_contents($xml_file, $doc->saveXML(), FILE_APPEND);
echo "Language xml generated successfully";

fclose($file);



Note: In this php code $filename = "multi-language-android-en.csv" is your csv file name.

Once you execute this code, it will create xml file like following image.



Download

Add Product Grid In Customer Admin Section And Save The Checkbox Values To Database - Magento 2

In one of my project i want to add product grid in Magento 2 admin customer section with a separate tab. And also want to save selected product checkbox value to my custom database. After spending 2 days i found solution after merging few codes that i found.

So i have created my custom magento 2 module that will do this all thing. It will add new tab in customer admin section and also save checkbox value to custom database.


Product Grid In Customer Admin Section


Here is the quick steps to create module.
OR
You can download module here,
Note: This module also include code to show selected product in front-end.
Download

Step1: HK/Productattach/registration.php
<?php

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

Step2: HK/Productattach/Block/Adminhtml/Edit/Tab/Products.php
<?php

namespace HK\Productattach\Block\Adminhtml\Edit\Tab;

use HK\Productattach\Model\ProductattachFactory;

class Products extends \Magento\Backend\Block\Widget\Grid\Extended
{
    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
     */
    private $productCollectionFactory;

    //private $attachModel;

    /**
     * @var ProductattachFactory
     */
    private $contactFactory;

    /**
     * @var \Magento\Framework\Registry
     */
    private $registry;

    /**
     * Products constructor.
     * @param \Magento\Backend\Block\Template\Context $context
     * @param \Magento\Backend\Helper\Data $backendHelper
     * @param \Magento\Framework\Registry $registry
     * @param ProductattachFactory $contactFactory
     * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
     * @param array $data
     */
    public function __construct(
        \Magento\Backend\Block\Template\Context $context,
        \Magento\Backend\Helper\Data $backendHelper,
        \Magento\Framework\Registry $registry,
        ProductattachFactory $contactFactory,
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
        array $data = []
    ) {
        $this->contactFactory = $contactFactory;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->registry = $registry;
        //$this->attachModel = $attachModel;
        parent::__construct($context, $backendHelper, $data);
    }

    /**
     * _construct
     * @return void
     */
    public function _construct()
    {
        parent::_construct();
        $this->setId('productsGrid');
        $this->setDefaultSort('entity_id');
        $this->setDefaultDir('DESC');
        $this->setSaveParametersInSession(true);
        $this->setUseAjax(true);
        if ($this->getRequest()->getParam('productattach_id')) {
        //if ($this->getRequest()->getParam('id')) {
            $this->setDefaultFilter(['in_product' => 1]);
        }
    }

    /**
     * @param \Magento\Backend\Block\Widget\Grid\Column $column
     * @return $this
     */
    public function _addColumnFilterToCollection($column)
    {
        if ($column->getId() == 'in_product') {
            $productIds = $this->_getSelectedProducts();

            if (empty($productIds)) {
                $productIds = 0;
            }
            if ($column->getFilter()->getValue()) {
                $this->getCollection()->addFieldToFilter('entity_id', ['in' => $productIds]);
            } else {
                if ($productIds) {
                    $this->getCollection()->addFieldToFilter('entity_id', ['nin' => $productIds]);
                }
            }
        } else {
            parent::_addColumnFilterToCollection($column);
        }

        return $this;
    }

    /**
     * prepare collection
     */
    public function _prepareCollection()
    {
        $collection = $this->productCollectionFactory->create();
        $collection->addAttributeToSelect('name');
        $collection->addAttributeToSelect('sku');
        $collection->addAttributeToSelect('price');
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

    /**
     * @return $this
     */
    public function _prepareColumns()
    {

        //$model = $this->attachModel;

        $this->addColumn(
            'in_product',
            [
                'header_css_class' => 'a-center',
                'type' => 'checkbox',
                'name' => 'in_product',
                'align' => 'center',
                'index' => 'entity_id',
                'values' => $this->_getSelectedProducts(),
            ]
        );

        $this->addColumn(
            'entity_id',
            [
                'header' => __('Product ID'),
                'type' => 'number',
                'index' => 'entity_id',
                'header_css_class' => 'col-id',
                'column_css_class' => 'col-id',
            ]
        );
        $this->addColumn(
            'names',
            [
                'header' => __('Name'),
                'index' => 'name',
                'class' => 'xxx',
                'width' => '50px',
            ]
        );
        $this->addColumn(
            'sku',
            [
                'header' => __('Sku'),
                'index' => 'sku',
                'class' => 'xxx',
                'width' => '50px',
            ]
        );
        $this->addColumn(
            'price',
            [
                'header' => __('Price'),
                'type' => 'currency',
                'index' => 'price',
                'width' => '50px',
            ]
        );

        return parent::_prepareColumns();
    }

    /**
     * @return string
     */
    public function getGridUrl()
    {
        return $this->getUrl('*/*/productsgrid', ['_current' => true]);
    }
    
    public function getTabUrl()
    {
        $id = 0;
        $customerId = $this->getRequest()->getParam('id');
        
        $_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $hkproductCollection = $_objectManager->create('HK\Productattach\Model\Productattach');
        $hkproductCollection = $hkproductCollection->getCollection()->addFieldToFilter('customer_id', $customerId);
        
        if($hkproductCollection->count() > 0){
            $id = $hkproductCollection->getFirstItem()->getId();
        }
        
        return $this->getUrl('productattach/*/products', ['productattach_id' => $id, '_current' => true]);
    }

    /**
     * @param  object $row
     * @return string
     */
    public function getRowUrl($row)
    {
        return '';
    }

    public function _getSelectedProducts()
    {
        $contact = $this->getContact();
        return $contact->getProducts($contact);
    }

    /**
     * Retrieve selected products
     *
     * @return array
     */
    public function getSelectedProducts()
    {
        $contact = $this->getContact();
        $selected = $contact->getProducts($contact);
        
        if (!is_array($selected)) {
            $selected = [];
        }
        return $selected;
    }

    public function getContact()
    {
        $contactId = $this->getRequest()->getParam('productattach_id');
        $contact = $this->contactFactory->create();
        
        if ($contactId) {
            $contact->load($contactId);
        }
        return $contact;
    }

    /**
     * {@inheritdoc}
     */
    public function canShowTab()
    {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function isHidden()
    {
        return true;
    }
    
    public function isAjaxLoaded()
    {
        return true;
    }
    
    public function getTabLabel()
    {
        return __('Customer Products');
    }

    /**
     * @return \Magento\Framework\Phrase
     */
    public function getTabTitle()
    {
        return __('Customer Products');
    }
}

Step3: HK/Productattach/Controller/Adminhtml/Index/Products.php
<?php

namespace HK\Productattach\Controller\Adminhtml\Index;

use Magento\Backend\App\Action;

class Products extends \Magento\Backend\App\Action
{
    /**
     * @var \Magento\Framework\View\Result\LayoutFactory
     */
    private $resultLayoutFactory;

    /**
     * Products constructor.
     * @param Action\Context $context
     * @param \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory
     */
    public function __construct(
        Action\Context $context,
        \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory
    ) {
        parent::__construct($context);
        $this->resultLayoutFactory = $resultLayoutFactory;
    }

    /**
     * @return bool
     */
    public function _isAllowed()
    {
        return true;
    }

    /**
     * Save action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {

        $resultLayout = $this->resultLayoutFactory->create();
        $resultLayout->getLayout()->getBlock('productattach.edit.tab.products')
                     ->setInProducts($this->getRequest()->getPost('index_products', null));

        return $resultLayout;
    }
}


Step4: HK/Productattach/Controller/Adminhtml/Index/ProductsGrid.php
<?php

namespace HK\Productattach\Controller\Adminhtml\Index;

use Magento\Backend\App\Action;

class ProductsGrid extends \Magento\Backend\App\Action
{

    /**
     * @var \Magento\Framework\View\Result\LayoutFactory
     */
    private $resultLayoutFactory;

    /**
     * ProductsGrid constructor.
     * @param Action\Context $context
     * @param \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory
     */
    public function __construct(
        Action\Context $context,
        \Magento\Framework\View\Result\LayoutFactory $resultLayoutFactory
    ) {
        parent::__construct($context);
        $this->resultLayoutFactory = $resultLayoutFactory;
    }

    /**
     * @return bool
     */
    public function _isAllowed()
    {
        return true;
    }

    /**
     * Save action
     *
     * @return \Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $resultLayout = $this->resultLayoutFactory->create();
        $resultLayout->getLayout()->getBlock('productattach.edit.tab.products')
                     ->setInBanner($this->getRequest()->getPost('index_products', null));

        return $resultLayout;
    }
}


Step5: HK/Productattach/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="HK_Productattach" setup_version="1.0.2">
        <sequence>
            <module name="Magento_Backend"/>
            <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>
            <module name="Magento_Catalog"/>
        </sequence>
    </module>
</config>

Step6: HK/Productattach/etc/adminhtml/routes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:App/etc/routes.xsd">
    <router id="admin">
        <route id="productattach" frontName="productattach">
            <module name="HK_Productattach" />
        </route>
    </router>
</config>

Step7: HK/Productattach/etc/adminhtml/events.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="adminhtml_customer_save_after">
        <observer name="customer_save_after" instance="HK\Productattach\Observer\Customersaveafter" />
    </event>
</config>

Step8: HK/Productattach/Model/Productattach.php
<?php
namespace HK\Productattach\Model;

class Productattach extends \Magento\Framework\Model\AbstractModel
{
    
    /**
     * Return unique ID(s) for each object in system
     *
     * @return array
     */
    public function getIdentities()
    {
        return [self::CACHE_TAG . '_' . $this->getId()];
    }
    
    /**
     * Initialize resource model
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('HK\Productattach\Model\ResourceModel\Productattach');
    }
    
    public function getProducts(\HK\Productattach\Model\Productattach $object)
    {
        $id = $object->getId();
        $tbl = $this->getResource()->getTable("hk_productattach");
        $select = $this->getResource()->getConnection()->select()->from(
            $tbl,
            ['products']
        )
        ->where(
            'productattach_id = ?',
            (int)$id
        );

        $products = $this->getResource()->getConnection()->fetchCol($select);
        
        if ($products) {
            $products = explode('&', $products[0]);
        }

        return $products;
    }
}

Step9: HK/Productattach/Model/ProductattachFactory.php
<?php

namespace HK\Productattach\Model;

class ProductattachFactory
{
    /**
     * @var \Magento\Framework\ObjectManagerInterface
     */
    protected $_objectManager;

    /**
     * @param \Magento\Framework\ObjectManagerInterface $objectManager
     */
    public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager)
    {
        $this->_objectManager = $objectManager;
    }

    /**
     * Create new country model
     *
     * @param array $arguments
     * @return \Magento\Directory\Model\Country
     */
    public function create(array $arguments = [])
    {
        return $this->_objectManager->create('HK\Productattach\Model\Productattach', $arguments, false);
    }
}

Step10: HK/Productattach/Model/ResourceModel/Productattach.php
<?php
namespace HK\Productattach\Model\ResourceModel;

class Productattach extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
    /**
     * Initialize resource model
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('hk_productattach', 'productattach_id');
    }
}

Step11: HK/Productattach/Model/ResourceModel/Productattach/Collection.php
<?php

namespace HK\Productattach\Model\ResourceModel\Productattach;

class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection
{

    /**
     * Define resource model
     *
     * @return void
     */
    protected function _construct()
    {
        $this->_init('HK\Productattach\Model\Productattach', 'HK\Productattach\Model\ResourceModel\Productattach');
        //$this->_map['fields']['page_id'] = 'main_table.page_id';
    }

}

Step12: HK/Productattach/Observer/Customersaveafter.php
<?php

namespace HK\Productattach\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;

class Customersaveafter implements ObserverInterface {

    protected $objectManager;

    public function __construct(
        \Magento\Framework\ObjectManagerInterface $objectManager
    ) {
        $this->objectManager = $objectManager;
    }

    public function execute(EventObserver $observer) {

        $customer = $observer->getEvent()->getData('customer');
        $products = $observer->getRequest()->getPost('products');
        
  $_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
  $hkproductModel = $this->objectManager->create('HK\Productattach\Model\Productattach');
  $hkproductCollection = $hkproductModel->getCollection()->addFieldToFilter('customer_id', $customer->getId());
  
  if($hkproductCollection->count() > 0){
   $hkproductCollection = $hkproductCollection->getFirstItem();
   $hkproductCollection->setProducts($products);
   $hkproductCollection->save();
  }else{
   if($products){
    $hkproductModel->setData(array('products'=>$products, 'customer_id' => $customer->getId()));
    $hkproductModel->save();
   }
  }
    }
}

Step13: HK/Productattach/Setup/InstallSchema.php
<?php

namespace HK\Productattach\Setup;

use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\DB\Adapter\AdapterInterface;

class InstallSchema implements InstallSchemaInterface {

    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) {
        $installer = $setup;

        $installer->startSetup();
        
  $installer->getConnection()->dropTable($installer->getTable('hk_productattach'));

  $hk_productattach = $installer->getConnection()->newTable($installer->getTable('hk_productattach'));

  $hk_productattach->addColumn(
   'productattach_id',
   \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
   null,
   ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
   'Entity Id'
  );

  $hk_productattach->addColumn(
   'customer_id',
   \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
   null,
   ['nullable' => true,'default' => null],
   'Customer ID'
  );

  $hk_productattach->addColumn(
   'products',
   \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
   null,
   ['nullable' => true,'default' => null],
   'Assigned Products'
  );

  $hk_productattach->addColumn(
   'created_at',
   \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
   null,
   ['nullable' => false],
   'Created At'
  );

  $installer->getConnection()->createTable($hk_productattach);
  $installer->endSetup();
  
        $installer->endSetup();
    }
}

Step14: HK/Productattach/view/adminhtml/layout/customer_index_edit.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left"
      xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="customer_form">
            <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="customer_edit_tab_products">
                <action method="setTabLabel">
                    <argument name="label" xsi:type="string">Customer Products</argument>
                </action>
            </block>
        </referenceBlock>
    </body>
</page>

Step15: HK/Productattach/view/adminhtml/layout/productattach_index_products.xml
<?xml version="1.0" encoding="UTF-8"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
    <container name="root" label="Root">
        <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="productattach.edit.tab.products"/>
        <block class="Magento\Backend\Block\Widget\Grid\Serializer" name="products_grid_serializer">
            <arguments>
                <argument name="grid_block" xsi:type="string">productattach.edit.tab.products</argument>
                <argument name="callback" xsi:type="string">getSelectedProducts</argument>
                <argument name="input_element_name" xsi:type="string">products</argument>
                <argument name="reload_param_name" xsi:type="string">index_products</argument>
            </arguments>
        </block>
        <block class="Magento\Framework\View\Element\Template" name="grid_scriptjs" template="HK_Productattach::scriptjs.phtml"/>
    </container>
</layout>

Step16: HK/Productattach/view/adminhtml/layout/productattach_index_productsgrid.xml
<?xml version="1.0" encoding="UTF-8"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
    <container name="root" label="Root">
        <block class="HK\Productattach\Block\Adminhtml\Edit\Tab\Products" name="productattach.edit.tab.products"/>
    </container>
</layout>

Step17: HK/Productattach/view/adminhtml/templates/scriptjs.phtml
<script>
    require([
        "jquery",

    ], function($){     
        $("input[name='products']").attr('data-form-part','customer_form');      
    });
</script>

Now run following commands and you are done.
php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy

I hope this will help someone.
Thanks

 

Copyright @ 2017 HKBlog.