Tuesday, February 10, 2015

Resolve the Bootstrap Tooltip conflict with jQuery UI Tooltip in Yii2

Encountered this issue when trying to get some tooltips working on my Yii2 web app which uses Bootstrap and some jQuery UI to jointly build the user interface. I noticed that the jQuery UI tooltips overrides the Bootstrap tooltip function. This is because they both share the same JavaScript namespace, $.fn.tooltip

You can avoid the conflict simply loading Bootstrap after jQury UI is loaded. But how you can do this in Yii2. You may do this using Yii2 Asset Manager configurations. Usually the Bootstrap Plugin Assets depend only on JqueryAsset and BootstrapAsset bundles. In order to load bootstrap.js after the jQury UI has loaded, you have to add it to the list of depending asset bundles of the BootstrapPluginAsset


...

'components' => [
       ...
        'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                    'sourcePath' => null,
                    'js' => [
                        '//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
                    ],
                ],
                'yii\bootstrap\BootstrapPluginAsset' => [
                    'js' => [
                        'js/bootstrap.min.js',
                    ],
                    'depends' => [
                        'yii\web\JqueryAsset',
                        'yii\jui\JuiAsset',
                        'yii\bootstrap\BootstrapAsset',
                    ],
                ],
            ],
        ],
    ],

... 


Not only for tooltips, this method may be useful in any situation where you want to load some resources before others, or in a particular order.

Read more about Asset Management in Yii2

Saturday, December 20, 2014

List.js widget for Yii2

List.js is a handy way of adding searching and sorting to HTML lists and tables. It allows searching trough a list of items with multiple data fields per item. Read more on how it works and try some examples here.

So, for the ones who are interested in using List.js in a Yii2 project, here is a simple widget for it.

Requirements

Yii 2.0 or above

Installation

The preferred way to install this extension is through composer.
Either run

php composer.phar require --prefer-dist nterms/yii2-listjs-widget "*"

or add

"nterms/yii2-listjs-widget": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :
<?= \nterms\listjs\ListJs::begin([ 
 'id' => 'days-list',
 'search' => true,
 'sort' => [
  'name' => [
   'label' => Yii::t('app', 'Sort by name'),
  ],
 ],
 'clientOptions' => [
  'valueNames' => ['name'],
 ],
]); ?>

<ul class="list">
 <li><div class="name">Sunday</div></li>
 <li><div class="name">Monday</div></li>
 <li><div class="name">Tuesday</div></li>
 <li><div class="name">Wednesday</div></li>
 <li><div class="name">Thursday</div></li>
 <li><div class="name">Friday</div></li>
 <li><div class="name">Saturday</div></li>
</ul>

<?= \nterms\listjs\ListJs::end(); ?>

Configurations

Following properties are available for customizing the widget.
  • options: HTML attributes for the container element.
  • search: Whether to show the search field.
  • searchOptions: HTML attributes (name-value pairs) for the search input tag.
  • sort: list of name-value pairs for rendering the sorting buttons list. Value being the HTML attributes for the button. Special parameter label is used as the button text
    ...
    'sort' => [
     'name' => [
      'class' => 'sort',
      'label' => Yii::t('app', 'Sort by name'),
     ],
    ],
    ...
    
  • clientOptions: Options for List.js. Read this for list of options.
  • content: HTML content, preferably a list or table. If the widget is used in content capturing mode this will be ignored.
  • view: Name of the view file to render the content. If the widget is used in content capturing mode or a string is assigned to content property this will be ignored.
  • viewParams: Parameters to be passed to view when it is being rendered. This property is used only when view is rendered to generate the content of the widget.

yii2-listjs-widget on github

Tuesday, September 9, 2014

Validate Yii2 forms before submitting with AJAX

I'm sure the code is much explanatory itself. Here is the solution. This would prevent the form being submitted the usual way while still the client validation is done.

<?php $form = ActiveForm::begin([
        'action' => ['create'],
        'enableAjaxValidation' = false,
        'enableClientValidation' = true,
        'beforeSubmit' => "function(form) {
        
                if($(form).find('.has-error').length) {
                        return false;
                }
                
                $.ajax({
                        url: form.attr('action'),
                        type: 'post',
                        data: form.serialize(),
                        success: function(data) {
                                // do something ...
                        }
                });
                
                return false;
        }",
]); ?>

This old method does not work anymore. Yii2 was updated lately to support more elegant way of handling JavaScript events. Please refer to:
https://github.com/yiisoft/yii2/pull/4955
https://github.com/yiisoft/yii2/issues/1350

Following code shows how you can use JS events to handle the same situation above.

Your php code remains same:
<?php $form = ActiveForm::begin([
        'id' => 'login-form',
        'action' => ['create'],
        'enableAjaxValidation' = false,
        'enableClientValidation' = true,
        
]); ?>

But the JavaScript part goes to a separate .js file:
$(document).ready(
        $('#login-form').on('beforeSubmit', function(event, jqXHR, settings) {
                var form = $(this);
                if(form.find('.has-error').length) {
                        return false;
                }
                
                $.ajax({
                        url: form.attr('action'),
                        type: 'post',
                        data: form.serialize(),
                        success: function(data) {
                                // do something ...
                        }
                });
                
                return false;
        }),
);

Sunday, October 6, 2013

Insert a new page to an existing PDF dynamically with PHP

This is a quick solution I found for one of the issues I got while developing a web portal which allows PDF downloads. However these PDF documents had to be preceded with a dynamically generated page which should be inserted at the time of downloading the PDF.

After few hours of trying I came up with this solution which worked well in my case. Just thought of sharing my solution for someone who might have the same issue.

This can be easily done using mPDF. Please download mPDF and follow the instructions on the mPDF documentation to get it working with your PHP application. I use Yii for my projects and mPDF is available for Yii as an extension (yii-pdf) which you can find here.

mPDF allows importing pages from another PDF into the one you create on the fly. We use this feature for importing all the pages of the source PDF file and create a new PDF inserting a dynamically generated page at start.

A plain PHP example:

include("../mpdf.php");

$pdf = new mPDF();
$pdf->AddPage();
$pdf->WriteHTML('Some HTML content for the first page');
      
$pdf->SetImportUse();
$pageCount = $pdf->SetSourceFile($model->getFile());
for($i = 1; $i <= $pageCount; $i++) {
 $pdf->AddPage();
 $tpl = $pdf->ImportPage($i);
 $pdf->UseTemplate($tpl);
}

// output as a file
$pdf->Output();
exit;

Same block of code in Yii compatible way. Please note that you need to setup yii-pdf extension as described in Yii extension page for yii-pdf.

$pdf = Yii::app()->mpdf->mpdf();
$pdf->AddPage();

$pdf->WriteHTML('Some HTML content for the first page');

$pdf->SetImportUse();
$pageCount = $pdf->SetSourceFile($model->getFile());
for($i = 1; $i <= $pageCount; $i++) {
 $pdf->AddPage();
 $tpl = $pdf->ImportPage($i);
 $pdf->UseTemplate($tpl);
}

// output as a file
$pdf->Output();
Yii::app()->end();


NOTE: This might not be the best way to do this. If you know a better method please leave a comment and let me know how did you do that :)

Thursday, July 19, 2012

PHP cURL issue with WAMP Server on Windows 7 (64 bit)

Just installed WampServer (64 bits & PHP 5.3) 2.2E recently on my new PC with Windows 7 Ultimate (64 bits). Initially cURL (php_curl.dll) was not loaded due to some reason.

Tried to enable the extension through wamp manager and, by directly editing the php.ini file, but failed. However after googling for few hours I found a fix. The problem was the curl extension that comes with the WampServer is not compatible with the system.

Here is the fix. Follow this link
http://www.anindya.com/php-5-4-3-and-php-5-3-13-x64-64-bit-for-windows/

Go to "Fixed curl extensions" and download the extension that matches your PHP version.

Extract and copy "php_curl.dll" to the extension directory of your wamp installation.
(i.e. C:\wamp\bin\php\php5.3.13\ext)

Restart Apache

Done!

Many thanks to Anindya for saving my time.

Friday, April 20, 2012

Yii CListView - JavaScript issue after pagination update

Yii CListView is a great tool when you want to show a set of data objects as a list in your web app. Everyone will bet the the most helping feature of CListView is the pagination. Simply you don't need to do anything to get pagination work on your list and even more importantly it's AJAX based. Means pages are loaded with AJAX making your application more interactive and user friendly.

So what's wrong with this amazing tool?

If you have HTML elements that needs to be accessed with JavaScript (more specifically jQuery, MooTools, Prototype or any JavaScript library), to attach some events or alter content dynamically when loading, they will work fine for the first page which is loaded in a normal HTTP request and not on the elements loaded with AJAX.

Let's say you want to attach an event to each list item with jQuery.


// the event handler
function clickHandler(evt) {
    // do something on click event
}

// assume that each item has the class "item" and id of list container is "itemList"
$('#itemList .item').bind('click', clickHandler);

Now, this would work only when you first load the page and the event handler will not be attached to the items loaded with subsequent pages you load with CListView pagination.
In order to deal with this kind of situations CListView provides a built in solution that we can use to attach our event handler to the items loaded with AJAX too. Simply set the afterAjaxUpdate property of CListView in your Yii view file as below.

// a javascript callback function to run when AJAX update is finish
$afterAjaxUpdate = 'function(id, data) { $("#itemList .item").bind("click", clickHandler); }';

widget('zii.widgets.CListView', array(
 'dataProvider'=>$dataProvider,
 'itemView'=>'_view',
 'id'=>'itemList',
 'afterAjaxUpdate'=>$afterAjaxUpdate
)); ?>

This way you may get even complex JavaScript operations done on your list items, that's up to you. Please do not forget to share your experience here, if possible.

Sunday, April 1, 2012

Twine - HTML based static website and documentation generator

Developing a static website or a HTML based documentation for something? Need to let your software users download the docs with the application? Want to use a common template across all the pages of your static website?

Well, this article is intended to help you with some basic but time consuming process of applying a template to an HTML based static website or and HTML based documentation. First think if you are developing a static website or documentation that has to follow the of rules given below.

  • All the files must be HTML files that has the extension .html
  • All the pages should share the same template without using a server side scripting language.
  • Files should be arranged in a folder based hierarchy for enabling easy access.
  • Whole website / documentation should be downloadable by end users for offline usage.
  • When published on the internet page URLs should be search engine friendly (SEO).
  • When browsing each page should contain a breadcrumb path for easy navigation.
  • Page title and description should be unique for each page.
  • Each page should be associated with a unique ID to make it easy to install social network plugins / widgets.
  • Pages should have breadcrumbs automatically generated.
Twine is a such tool that you can use to get all the above things done and generate a nice static website. However this tool is still in it's beta release. I leave it to you to experiment and use it in a creative way.

The GitHub repository is here.

Please don't forget to share your experience here.