Category Archives: backbone

Twitter bootstrap confirm dialog

Much time has passed since my last post. Had a lot of job… So I decided to write at least a small post. Today I share with you how I implemented analog of javascript confirm dialog using twitter bootstrap.

Nothing fancy 🙂

So let’s go. As usual I like to create base app object, that will handle common tasks – dislpay errors, keep some app data etc. And I implement it confirm function for it

$(document).ready(function() {
    window.app = {
      ...
      confirm: function(title, text, callback) {
        var confirmPopupHtml;
        confirmPopupHtml = JST['app/confirm']({
          'title': title,
          'confirm_message': text
        });
        $(window.document.body).append(confirmPopupHtml);
        $('#confirmModal').modal({});
        return $('#confirm_yes').on('click', function() {
          $('#confirmModal').modal('hide');
          return callback.call();
        });
      },
    }
    ...
})

What is interesting here – as you see I use underscore _.template function to render dialog. And i just pass callback function if user confirms the action. Javascript template is following

<!-- Modal -->
<div id="confirmModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="conrirm_label" aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
    <h3 id="conrirm_label"><%= title %></h3>
  </div>
  <div class="modal-body">
    <p><%= confirm_message %></p>
  </div>
  <div class="modal-footer">
    <button class="btn danger" id="confirm_yes">OK</button>
    <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
  </div>
</div>

And finally the example of usage.

window.app.confirm("Confirm delete", "Are you sure you want to delete selected row?", function() {
    // delete functionality
});

Yii and backbone js

I tried Backbone.js. Very nice js library BTW. It’s quite simple but at same time have nice functionality – all you need in order to make your frontend smarter. That’s why I like it. I’d call it jquery style he-he 🙂 – small but powerful.
As I remember Backbone js has grown from some rails project. So it has nice integration with rails.
But I tried to use it with yii. And I need to add some tricks in order to make it work.

So first of all backbone JS sends all info decoded by JSON. You can change data type. But this is way for dweebs (joking :). Unfortunatelly yii has some problems with JSON decoded data and REST. So let’s look what we have

public function getPost($name,$defaultValue=null)
{
return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
}

In our case POST data will be in “Request Payload” header i.e. we need to use getRawData function to fetch it (or getRestParams() inorder to fetch and parse data)
But look at getRestParams

if(function_exists('mb_parse_str')) {
    mb_parse_str($this->getRawBody(), $result);
} else {
    parse_str($this->getRawBody(), $result);
}

But in our case we have JSON data. I’ve added pull request (btw my first pull request to yii). Shortly we still talking on it. Not sure will it be approved or declined. But you can find it here https://github.com/yiisoft/yii/pull/2059 and here  Yii forum thread.
In the mean time here’s my custom HttpRequest component. They key is to check $_SERVER[‘CONTENT_TYPE’] and decode before parsing.


<?php

namespace Rz\components;

class HttpRequest extends \CHttpRequest
{

    protected $_restParams;

	/**
	 * Returns request parameters. Typically PUT or DELETE.
	 * @return array the request parameters
	 * @since 1.1.7
	 * @since 1.1.13 method became public
	 */
	public function getRestParams()
	{
		if($this->_restParams===null)
		{
			$result=array();
            if ($this->_isJsonEncoded()) {
                $result = \CJSON::decode($this->getRawBody());
            } else {
                if(function_exists('mb_parse_str')) {
                    mb_parse_str($this->getRawBody(), $result);
                } else {
                    parse_str($this->getRawBody(), $result);
                }
            }

			$this->_restParams=$result;
		}

		return $this->_restParams;
	}


    /**
	 * Returns the named POST parameter value.
	 * If the POST parameter does not exist, the second parameter to this method will be returned.
	 * @param string $name the POST parameter name
	 * @param mixed $defaultValue the default parameter value if the POST parameter does not exist.
	 * @return mixed the POST parameter value
	 * @see getParam
	 * @see getQuery
	 */
	public function getPost($name,$defaultValue=null)
	{
        if ($this->_isJsonEncoded()) {
            $data = \CJSON::decode($this->getRawBody());
            return isset($data[$name]) ? $data[$name] : $defaultValue;
        } else {
            return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
        }
	}

    /**
	 * Returns the named DELETE parameter value.
	 * If the DELETE parameter does not exist or if the current request is not a DELETE request,
	 * the second parameter to this method will be returned.
	 * If the DELETE request was tunneled through POST via _method parameter, the POST parameter
	 * will be returned instead (available since version 1.1.11).
	 * @param string $name the DELETE parameter name
	 * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist.
	 * @return mixed the DELETE parameter value
	 * @since 1.1.7
	 */
	public function getDelete($name,$defaultValue=null)
	{
		if($this->getIsDeleteViaPostRequest())
			return $this->getPost($name, $defaultValue);

		if($this->getIsDeleteRequest())
		{
			$this->getRestParams();
			return isset($this->_restParams[$name]) ? $this->_restParams[$name] : $defaultValue;
		}
		else
			return $defaultValue;
	}

	/**
	 * Returns the named PUT parameter value.
	 * If the PUT parameter does not exist or if the current request is not a PUT request,
	 * the second parameter to this method will be returned.
	 * If the PUT request was tunneled through POST via _method parameter, the POST parameter
	 * will be returned instead (available since version 1.1.11).
	 * @param string $name the PUT parameter name
	 * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist.
	 * @return mixed the PUT parameter value
	 * @since 1.1.7
	 */
	public function getPut($name,$defaultValue=null)
	{
		if($this->getIsPutViaPostRequest())
			return $this->getPost($name, $defaultValue);

		if($this->getIsPutRequest())
		{
			$this->getRestParams();
			return isset($this->_restParams[$name]) ? $this->_restParams[$name] : $defaultValue;
		}
		else
			return $defaultValue;
	}

    /**
     * Check is request encoded in JSON
     * @return bool
     */
    protected function _isJsonEncoded()
    {
        if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') === 0) {
            return true;
        }
        return false;
    }
}

And one more note. If you want to use csrf verification perhaps you need to add such trick to your js

  $(document).ajaxSend(function(event, request, settings) {
    var data;
    if (settings.data) {
      data = jQuery.parseJSON(settings.data);
      data['YII_CSRF_TOKEN'] = $.cookie('YII_CSRF_TOKEN');
      settings.data = JSON.stringify(data);
    } else {
      settings.data = "YII_CSRF_TOKEN=" + encodeURIComponent($.cookie('YII_CSRF_TOKEN'));
    }
  });