Knockout
, безусловно, весьма мощная библиотека, которая позволяет сэкономить море времени, но некоторые моменты в её работе, мне показались неудобными. Про один из них эта заметка. Binding
«click
» просит указать метод, но особенности JavaScript
-а, не позволяют удобным способом указать метод и объект this
, для его вызова. В итоге мы имеем вот такие вот уродливые конструкции
<span data-bind="click: $root.save.bind($root)"></span> <span data-bind="click: $root.edit.bind($root, 'someParameter')"></span>
У меня возникло желание как это дело упростить. Я решил остановиться на таком варианте:
<span data-bind="click: @save"></span> <span data-bind="click: [@edit, 'someParameter']"></span>
Возможно, не очень очевидный синтаксис, но никто не мешает придумать свой :) Итак, задача состоит в том, чтобы заставить knockout
эти конструкции принимать за нужный метод. Для этого воспользуемся хаком preprocess
для binding
-а click
. У меня получилось примерно так:
ko.bindingHandlers.click.preprocess = function( val ) { val = $.trim( val ); if( val[ 0 ] === '@' ) { var method = val.substr( 1 ); return 'function(){ return $root["' + method + '"].apply( $root, arguments ); }'; } if( val[ 0 ] === '[' && val[ val.length - 1 ] === ']' ) { val = $.trim( val.substr( 1, val.length - 2 ) ); var params = val.split( /\s*,\s*/ ); if( params[ 0 ] && params[ 0 ][ 0 ] === '@' ) { var method = params.shift().substr( 1 ); var args = params.join(', '); var js = 'function()\n' + '{\n' + '\tvar args = [ ' + params + ' ].concat( _.toArray( arguments ) );\n' + '\treturn $root["' + method + '"].apply( $root, args );\n' + '}'; return js; } } return val; }
Решение пока черновое и не обкатанное. К тому же на click
-е мир клином не сошёлся и нужно что-то более универсальное.