diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 2502d48..ab642d4 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -23,5 +23,6 @@ Here list of differences to help you to upgrade your application:
 [enh] api method 'setValue' to set manually value of editable.
 [change] locales directory is excluded from bootstrap-datepicker input. If you need localization you should jus download corresponding file from github.
 [change] date and dateui specific options can be set only via 'datepicker' option in first level of config (previously it was possible to set some options directly in config, e.g. weekStart).
+[change] if 'url' option defined as function - it is used as submit method instead of ajax (previously it was dynamically return url string and ajax occured anyway)
 
 Also all known bugs of bootstrap-editable were closed.
\ No newline at end of file
diff --git a/src/containers/editable-container.js b/src/containers/editable-container.js
index efe4bc9..75704c2 100644
--- a/src/containers/editable-container.js
+++ b/src/containers/editable-container.js
@@ -123,7 +123,7 @@ Applied as jQuery method.
                 this.hide();
             }
             /**        
-            Fired when new value was submitted
+            Fired when new value was submitted. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
             
             @event save 
             @param {Object} event event object
@@ -133,8 +133,9 @@ Applied as jQuery method.
             @example
             $('#username').on('save', function(e, params) {
                 //assuming server response: '{success: true}'
+                var pk = $(this).data('editableContainer').options.pk;
                 if(params.response && params.response.success) {
-                    alert('value ' + params.newValue + ' saved!');
+                    alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
                 } else {
                     alert('error!'); 
                 } 
@@ -151,6 +152,7 @@ Applied as jQuery method.
         @param {mixed} value 
         **/         
         option: function(key, value) {
+            this.options[key] = value;
             if(key in this.containerOptions) {
                 this.containerOptions[key] = value;
                 this.setContainerOption(key, value); 
diff --git a/src/editable-form/editable-form.js b/src/editable-form/editable-form.js
index 172581c..ea33cfe 100644
--- a/src/editable-form/editable-form.js
+++ b/src/editable-form/editable-form.js
@@ -174,7 +174,7 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
                this.$container.triggerHandler('save', {newValue: newValue, response: response});
             }, this))
             .fail($.proxy(function(xhr) {
-               this.error(xhr.responseText || xhr.statusText || 'Unknown error!'); 
+               this.error(typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!'); 
                this.showForm();  
             }, this));
         },
@@ -196,13 +196,16 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
                     pk: pk 
                 });
 
-                //send ajax to server and return deferred object
-                return $.ajax({
-                    url     : (typeof this.options.url === 'function') ? this.options.url.call(this) : this.options.url,
-                    data    : params,
-                    type    : 'post',
-                    dataType: 'json'
-                });
+                if(typeof this.options.url === 'function') { //user's function
+                    return this.options.url.call(this, params);
+                } else {  //send ajax to server and return deferred object
+                    return $.ajax({
+                        url     : this.options.url,
+                        data    : params,
+                        type    : 'post',
+                        dataType: 'json'
+                    });
+                }
             }
         }, 
         
@@ -268,11 +271,21 @@ Editableform is linked with one of input types, e.g. 'text' or 'select'.
         **/
         type: 'text',
         /**
-        Url for submit
+        Url for submit, e.g. <code>post.php</code>  
+        If function - it will be called instead of ajax. Function can return deferred object to run fail/done callbacks.
 
         @property url 
         @type string|function
         @default null
+        @example
+        url: function(params) {
+           if(params.value === 'abc') {
+               var d = new $.Deferred;
+               return d.reject('field cannot be "abc"'); //returning error via deferred object
+           } else {
+               someModel.set(params.name, params.value); //save data in some js model
+           }
+        }        
         **/        
         url:null,
         /**
diff --git a/src/element/editable-element.js b/src/element/editable-element.js
index 6317ff3..7190ff4 100644
--- a/src/element/editable-element.js
+++ b/src/element/editable-element.js
@@ -286,6 +286,26 @@ Makes editable any HTML element on the page. Applied as jQuery method.
             
             this.hide();
             this.setValue(params.newValue);
+            
+            /**        
+            Fired when new value was submitted. You can use <code>$(this).data('editable')</code> inside handler to access to editable instance
+            
+            @event save 
+            @param {Object} event event object
+            @param {Object} params additional params
+            @param {mixed} params.newValue submitted value
+            @param {Object} params.response ajax response
+            @example
+            $('#username').on('save', function(e, params) {
+                //assuming server response: '{success: true}'
+                var pk = $(this).data('editable').options.pk;
+                if(params.response && params.response.success) {
+                    alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
+                } else {
+                    alert('error!'); 
+                } 
+            });
+            **/              
         },
 
         validate: function () {
diff --git a/test/unit/text.js b/test/unit/text.js
index 25e2c05..3d5c9ca 100644
--- a/test/unit/text.js
+++ b/test/unit/text.js
@@ -240,7 +240,33 @@ $(function () {
            start();  
         }, timeout);             
         
-      })              
+      });
+      
+     asyncTest("submit to url defined as function", function () {
+        expect(3);
+        var newText = 'qwe',
+            e = $('<a href="#" data-pk="1" id="a"></a>').appendTo(fx).editable({
+            url: function(params) {
+               ok(params.value, newText, 'new text passed in users function');
+               var d = new $.Deferred;
+               return d.reject('my error');
+            }
+        });
+        
+        e.click();                       
+        var p = tip(e);
+
+        ok(p.find('input[type=text]').length, 'input exists')
+        p.find('input').val(newText);
+        p.find('form').submit();
+        
+        setTimeout(function() {
+           equal(p.find('.editable-error-block').text(), 'my error', 'error shown correctly');                  
+           e.remove();    
+           start();  
+        }, timeout);           
+        
+     });  
      
      asyncTest("should show emptytext if entered text is empty", function () {
             var emptytext = 'blabla',