0

I am looking for some solution to make javascript run before phtml code.

My work is sends width and height of my screen to controller, and it will send back to phtml file(because we cant check width and height with php code, we have to do it in javascript code).

But for some reason, the ajax is called after phtml code.
So it makes an issue because the data was not sended from ajax.
Here is my phtml file

C:\xampp\htdocs\magento\app\code\Aht\BannerSlider\view\frontend\templates\index.phtml

<?php /** @var Aht\BannerSlider\Block\Frontend\Index $block */ ?>
<div>
    <?php
        if($block->checkAllowedPage()):
            foreach($block->checkAllowedPage() as $rowsBannerPage):
                $banner_id = $rowsBannerPage['banner_id'];
                if(!empty($block->getBannerSlideById($banner_id))):
    ?>
    <div class="slick-custom">
        <div class="banner-slider">
            <?php
                foreach($block->getBannerSlideById($banner_id) as $rowsBannerSlide):
            ?>
                    <?php
                        $slide = $block->getSlideById($rowsBannerSlide['slide_id']);

                        // resize img
                        $image = $this->helper('Aht\BannerSlider\Helper\Image');

                        $block->getResolutionScreen();
                        $resolition_screen = $image->getResolutionScreen();
                        $width = $resolition_screen[0];
                        $height = $resolition_screen[1];
                    ?>
<!--                1366,768 = max width màn hình -->
                    <div><img src="<?php echo $image->resize($slide->getImage(), $width, $height); ?>" style="width: 100%; height: auto;"></div>
            <?php
                endforeach;
            ?>
        </div>
        <div class="slick-arrows-custom">
            <i class="prev fa fa-arrow-circle-left"></i>
            <i class="next fa fa-arrow-circle-right"></i>
        </div>
    </div>
    <?php endif; ?>

    <?php
        endforeach;
    ?>
                <script>
                    require([
                        'jquery',
                        'slick'
                    ], function ($) {
                        $(document).ready(function () {
                            $('.banner-slider').each(function(){
                            $(this).slick({
                                    speed: 300,
                                    autoplay: true,
                                    arrows: true,
                                    prevArrow: $(this).parents('.slick-custom').find('.prev'),
                                    nextArrow: $(this).parents('.slick-custom').find('.next'),
                                    responsive: [
                                        {
                                            fade: true,
                                            breakpoint: 480,
                                            settings: {
                                                dots: true
                                            }
                                        }
                                    ]
                                });
                            });
                            $.ajax({
                                url: 'http://localhost/magento/banner/slide/image',
                                method: 'GET',
                                data: {
                                    width: screen.width,
                                    height: screen.height
                                }
                            });
                        });
                    });
                </script>
    <?php
        endif;
    ?>
</div>

It return issue with $width and $height because it return null.

Okay so if you need more information or code to check.

1

You can put the AJAX call inside slick. Then use the event afterChange to trigger your AJAX after the slider is loaded.

<script>
    require([
        'jquery',
        'slick'
    ], function ($) {
        $(document).ready(function () {
            $('.banner-slider').each(function(){
            $(this).slick({
                    speed: 300,
                    autoplay: true,
                    arrows: true,
                    prevArrow: $(this).parents('.slick-custom').find('.prev'),
                    nextArrow: $(this).parents('.slick-custom').find('.next'),
                    responsive: [
                        {
                            fade: true,
                            breakpoint: 480,
                            settings: {
                                dots: true
                            }
                        }
                    ],
                    init: function(){
                        $.ajax({
                            url: 'http://localhost/magento/banner/slide/image',
                            method: 'GET',
                            data: {
                                width: screen.width,
                                height: screen.height
                            }
                        });
                    }
                });
            });

        });
    });
</script>

Ref: Official Github

======Update on 16 Aug 2018 15:49======

If you want to resize the slick slider on resize you can simply insert this code into JS:

$(window).resize(function() {
    $('.banner-slider').slick('resize');
});

So that the result will look like this:

<script>
    require([
        'jquery',
        'slick'
    ], function ($) {
        $(document).ready(function () {
            $('.banner-slider').each(function(){
                $(this).slick({
                    speed: 300,
                    autoplay: true,
                    arrows: true,
                    prevArrow: $(this).parents('.slick-custom').find('.prev'),
                    nextArrow: $(this).parents('.slick-custom').find('.next'),
                    responsive: [
                        {
                            fade: true,
                            breakpoint: 480,
                            settings: {
                                dots: true
                            }
                        }
                    ],
                    init: function(){
                        $.ajax({
                            url: 'http://localhost/magento/banner/slide/image',
                            method: 'GET',
                            data: {
                                width: screen.width,
                                height: screen.height
                            }
                        });
                    }
                });
            });
            $(window).resize(function() {
                $('.banner-slider').slick('resize');
            });
        });
    });
</script>

Source: Github Ticket

  • Thanks for reply :) But i thing you are misunderstood me. I want to send it before all phtml code, wasn't in slick call. Because there need an image to slick, and right now, without the ajax call, i dont have any image to make a slick slider. :) – fudu Aug 16 '18 at 7:27
  • How about using init? It will run your AJAX call before the slider load – PY Yick Aug 16 '18 at 7:30
  • Okay so, right now, it need at least 1 img to run into slick slider right? But right now i dont have any image because the ajax is not called success. – fudu Aug 16 '18 at 7:31
  • So i cant do anything with slick slider right now. – fudu Aug 16 '18 at 7:31
  • You don't need to load the 1st image to get the screen width and height. It can calculate automatically – PY Yick Aug 16 '18 at 7:33
0

Now a days we have option in CSS to detect window width .

you can check this here : https://web-design-weekly.com/2014/11/18/viewport-units-vw-vh-vmin-vmax/

vw : means view width

100 vw means 100% of width .

This will surely solve your issue very efficiently and in optimized speedy way. Try and let me know your feedback . Thanks

  • hold up, so how to send my screen solution from css to php code? – fudu Aug 16 '18 at 7:29
  • create a "class" in html tag and pass in ajax or any front end html element. class can be added in style css file . thanks Let me know if any confusion. – Ramesh Chauhan Aug 16 '18 at 7:36
  • so we still have to use ajax to send information? – fudu Aug 16 '18 at 7:40
  • So what's the diffrence? :'( – fudu Aug 16 '18 at 7:41
  • your query : "But for some reason, the ajax is called after phtml code." You need to know that server side code will run first then client side javascript code will run or execute . Hence to make it more appropriate you must try to call complete block or controller in ajax . Hope that will surely solve ur issue . – Ramesh Chauhan Aug 16 '18 at 8:17
0

Ok so my leader give me the answer, and also, thanks for helping of @Ramesh Chauhan and @PY Yick, they helped me a lot :')

So here is the idea:
Instead of find the solution to make javascript run before all phtml code, we will make 2 file phtml, the first one use ajax to send data to a new action, and we have to create 1 new action to catch that ajax data.
And then, we do stuff in that new action with the data we passed throught ajax.(do stuff here is hard to explain, so please look at my code to understand that :'< , sorry about that)
After that, we create a new div and call success function() in ajax and append the html to that new div we just created before.

So here is the code i've done and success:

C:\xampp\htdocs\magento\app\code\Aht\BannerSlider\view\frontend\templates\index.phtml

This file is the first phtml file and also, it the one who have ajax.

<?php
$check = $this->helper('Aht\BannerSlider\Helper\Check');
if ($check->checkAllowedPage() != false):
    $full_route = $check->checkAllowedPage();
    ?>
    <div id="banner_slide_after_ajax_loaded"></div>
    <script>
        require([
            'jquery'
        ], function ($) {
            $(document).ready(function () {
                $.ajax({
                    url: 'http://localhost/magento/banner/slide/image',
                    method: 'GET',
                    dataType: 'html', // muốn render html thì cần phải có dòng này.
                    data: {
                        width: screen.width,
                        height: screen.height,
                        full_route: '<?php echo $full_route; ?>'
                    },
                    success: function (response) {
                        response = $.parseJSON(response);
                        // if (response.error) {
                        //     alert('failed');
                        // } else {
                            $('#banner_slide_after_ajax_loaded').append(response.html);
                        // }

                    }
                });

            });
        });
    </script>

<?php endif; ?>

You see the url: 'http://localhost/magento/banner/slide/image', right? Its the new action that i mentioned.
So here is it:

C:\xampp\htdocs\magento\app\code\Aht\BannerSlider\Controller\Slide\Image.php

This is controller of the new action, which catch the ajax data and do stuff, and then return $respone. And ajax use that respone in the success function(), take a look at my ajax code.
The key in here is this code:

$html = $resultPage->getLayout()
        ->createBlock('Aht\BannerSlider\Block\Frontend\Slide')
        ->setTemplate('Aht_BannerSlider::slide.phtml')
        ->toHtml();


This code call to a new block and new phtml file, which will be the content of response.html which i've call in success function in ajax

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 17/07/2018
 * Time: 4:35 CH
 */

namespace Aht\BannerSlider\Controller\Slide;

class Image extends \Magento\Framework\App\Action\Action
{
    protected $_pageFactory;

    protected $coreRegistry;

    protected $resultJsonFactory;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\Registry $coreRegistry,
        \Magento\Framework\View\Result\PageFactory $pageFactory,
        \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
    )
    {
        $this->coreRegistry = $coreRegistry;
        $this->_pageFactory = $pageFactory;
        $this->resultJsonFactory = $resultJsonFactory;
        return parent::__construct($context);
    }

    public function execute()
    {
//      gửi width,height và full_route qua block bằng register

        $width = $this->getRequest()->getParam('width');
        $height = $this->getRequest()->getParam('height');
        $full_route = $this->getRequest()->getParam('full_route');

        $resolution_screen = array($width,$height);

        $this->coreRegistry->register('resolution_screen', $resolution_screen);
        $this->coreRegistry->register('full_route', $full_route);

        $resultPage = $this->_pageFactory->create();

        $html = $resultPage->getLayout()
            ->createBlock('Aht\BannerSlider\Block\Frontend\Slide')
            ->setTemplate('Aht_BannerSlider::slide.phtml')
            ->toHtml();

        $resultJson = $this->resultJsonFactory->create();

        $error = false;

        $respone = $resultJson->setData(['html' => $html, 'error' => $error]);

//        $result = ['html' => $html, 'error' => false];

//        if(true) {
//            $result['error'] = true;
//        }

        return $respone;
    }
}



Okay, that's all you need to know to make this works. And if you want to know more about the slide.phtml and block that i mentioned up there, please let me know.

Thanks for helping me, happy coding :')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.