Symfony Knockout:自定义绑定处理程序无法收听绑定处理程序
Symfony Knockout: Custom Binding Handler cannot listen to the binding handler
在我的 symfony 3 项目中,我制作了一个表格,我想使用 knockout.js 通过 ajax 提交。但对于某些人来说,它会使浏览器重定向到操作而不是通过 ajax.
我想在名为 app/FosUserBundle/views/Registration/register.html.twig
的文件中使用 ajax 提交的表单是:
{% extends "FOSUserBundle::layout.html.twig" %}
{% block fos_user_content %}
{% form_theme form '::themes/register-form-theme.html.twig' %}
{% trans_default_domain 'FOSUserBundle' %}
<div class="container" data-bind="with:registerVm">
<div class="register-box">
<div class="register-logo">
<h1>PhotoShare!</h1>
</div>
<div class="register-box-body">
<p class="login-box-msg">Register a new membership</p>
{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'),'attr':{'data-bind':'formSubmitAjax:\{\'success\':registerComplete\}'}}) }}
{{ form_widget(form) }}
<div class="row">
<div class="col-xs-4">
<input type="submit" class="btn btn-primary btn-block btn-flat" value="{{ 'registration.submit'|trans }}" />
</div>
</div>
{{ form_end(form) }}
</div>
</div>
{% endblock fos_user_content %}
表单需要使用以下 knockout.js 自定义绑定处理程序:
define(['knockout','jquery'],function(ko,$)
{
ko.bindingHandlers.formSubmitAjax={
init: function(element, valueAccessor, allBindingsAccessor)
{
var callbacks=valueAccessor();
var action=$(element).attr('action');
var method=$(element).attr('method');
var dataType=(callbacks && callbacks['type'])?callbacks['type']:'json';//By default use Json
$(element).submit(function(e)
{
e.preventDefault();
var form_data= $(this).serialize();
$.ajax({
'method':method,
'data':form_data,
'url':action,
'beforeSend':function()
{
if(typeof callbacks['beforeSend'] === 'function') callbacks['beforeSend']();
},
'success':function(data,textStatus,jqXHR)
{
if(typeof callbacks['success'] === 'function') callbacks['success'](data,textStatus,jqXHR);
},
'error':function(jqXHR,textStatus,errorThrown)
{
if(typeof callbacks['error'] === 'function') callbacks['error'](jqXHR,textStatus,errorThrown);
},
'complete':function(jqXHR,textStatus)
{
if(typeof callbacks['always'] === 'function') callbacks['always'](jqXHR,textStatus);
}
});
});
}
};
})
此表单通过 pager.js 在此 twig 模板上呈现:
{% extends "base.html.twig" %}
{% set classes=''%}
{% block javascriptsHeader %}
<script src="{{asset('assets/vendor/require.js')}}" data-main="{{path('main_javascript')}}" ></script>
{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" type="text.css" href="{{ asset('assets/vendor/xeditable/css/bootstrap-editable.css') }}" >
<style>
#message-area{
z-index:9999;
}
.page{
min-height:100%;
min-width:100%;
}
</style>
{% endblock %}
{% block body %}
<div id="message-area"></div>
<div class="hold-transition register-page page" data-bind="page: {id:'register', title:'Register', role:'start', sourceOnShow: '{{ path('fos_user_registration_register') }}', withOnShow:function(a){registerVm.init();},with:registerVm}"></div>
{% endblock %}
扩展了以下基本模板:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/bootstrap/css/bootstrap.css')}}" >
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/adminlte/adminlte.css')}}" >
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/adminlte/skin-blue.css')}}" >
{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
{% block javascriptsHeader %}
{% endblock %}
</head>
<body class="{{ classes }}">
{% block body %}
{% endblock body %}
{% block javascriptsFooter %}
{% endblock javascriptsFooter %}
</body>
</html>
所有必需的 javascript 我通过以下 require.js 模板呈现它:
requirejs.config({
baseUrl:'{{asset('assets')}}',
paths:{
'text':'{{ asset('assets/vendor/text') }}',
'knockout':'{{ asset('assets/vendor/knockout') }}',
'pager':"{{asset('assets/vendor/pager')}}",
'bootstrap':"{{asset('assets/vendor/bootstrap/js/bootstrap')}}",
'jquery':"{{asset('assets/vendor/jquery')}}",
'jquery_ui':"{{ asset('assets/vendor/jquery-ui') }}",
'xeditable_bootstrap':"{{ asset('assets/vendor/xeditable/xeditable') }}",
'ko_xeditable':"{{ asset('assets/vendor/knockout/knockout.x-editable') }}",
'jquery-fileupload':"{{ asset('assets/vendor/jquery_fileupload/jquery.fileupload') }}",
'jquery-iframe':"{{ asset('assets/vendor/jquery_fileupload/jquery.iframe-transport') }}",
'jquery-ui-widget':"{{ asset('assets/vendor/jquery_fileupload/jquery.ui.widget') }}",
'masterViewModel':"{{ asset('assets/js/viewModels/masterViewModel') }}",
'registerViewModel':"{{ asset('assets/js/viewModels/registerPageViewModel') }}",
{% block Viewmodels %}
{% endblock %}
'formPost':"{{ asset('assets/js/bindingHandlers/formPost') }}",
'compMessage':"{{ asset('assets/js/components/message/message') }}",
'extBooleanToggle':'assets/js/extenders/booleanToggle',
},
shim:{
'pager': ['jquery', 'knockout'],
'jquery_ui':['jquery'],
'bootstrap':['jquery'],
'xeditable_bootstrap':['jquery-ui','bootstrap'],
'ko_xeditable':['xeditable_bootstrap'],
'jquery-fileupload':['jquery-iframe','jquery-ui-widget'],
'jquery-ui-widget':['jquery_ui'],//Jquery_ui already load jquery
'jquery-iframe':['jquery']
{% block CustomShim %}
{% endblock %}
},
waitSeconds: 200,
});
define(['jquery','knockout','pager','masterViewModel','bootstrap'],function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
knockout 和 pager.js 初始化的主视图模型如下:
define(['knockout','jquery','registerViewModel'],function(ko,$,registervm){
function MasterViewModel()
{
var self=this;
self.registerVm=new registervm(self);
}
return new MasterViewModel();
})
你们知道为什么 formSubmitAjax
没有被调用吗?
您需要确保在调用 ko.applyBindings
之前加载绑定处理程序。像这样:
define(['jquery','knockout','pager','masterViewModel','bootstrap', 'formPost'], function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
我将以下内容放在 require.js shim
部分并且非常有效:
'masterViewModel':['registerViewModel'],
'registerViewModel':['formPost']
结果如下main.js.twig
requirejs.config({
baseUrl:'{{asset('assets')}}',
paths:{
'text':'{{ asset('assets/vendor/text') }}',
'knockout':'{{ asset('assets/vendor/knockout') }}',
'pager':"{{asset('assets/vendor/pager')}}",
'bootstrap':"{{asset('assets/vendor/bootstrap/js/bootstrap')}}",
'jquery':"{{asset('assets/vendor/jquery')}}",
'jquery_ui':"{{ asset('assets/vendor/jquery-ui') }}",
'xeditable_bootstrap':"{{ asset('assets/vendor/xeditable/xeditable') }}",
'ko_xeditable':"{{ asset('assets/vendor/knockout/knockout.x-editable') }}",
'jquery-fileupload':"{{ asset('assets/vendor/jquery_fileupload/jquery.fileupload') }}",
'jquery-iframe':"{{ asset('assets/vendor/jquery_fileupload/jquery.iframe-transport') }}",
'jquery-ui-widget':"{{ asset('assets/vendor/jquery_fileupload/jquery.ui.widget') }}",
'masterViewModel':"{{ asset('assets/js/viewModels/masterViewModel') }}",
'registerViewModel':"{{ asset('assets/js/viewModels/registerPageViewModel') }}",
{% block Viewmodels %}
{% endblock %}
'formPost':"{{ asset('assets/js/bindingHandlers/formPost') }}",
//'debug':"{{ asset('assets/js/bindingHandlers/debug') }}",
'compMessage':"{{ asset('assets/js/components/message/message') }}",
'extBooleanToggle':'assets/js/extenders/booleanToggle',
},
shim:{
'pager': ['jquery', 'knockout'],
'jquery_ui':['jquery'],
'bootstrap':['jquery'],
'xeditable_bootstrap':['jquery-ui','bootstrap'],
'ko_xeditable':['xeditable_bootstrap'],
'jquery-fileupload':['jquery-iframe','jquery-ui-widget'],
'jquery-ui-widget':['jquery_ui'],//Jquery_ui already load jquery
'jquery-iframe':['jquery'],
'masterViewModel':['registerViewModel'],
'registerViewModel':['formPost']
{% block CustomShim %}
{% endblock %}
},
waitSeconds: 200,
});
define(['jquery','knockout','pager','masterViewModel','bootstrap'],function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
工作起来很有魅力!!!
在我的 symfony 3 项目中,我制作了一个表格,我想使用 knockout.js 通过 ajax 提交。但对于某些人来说,它会使浏览器重定向到操作而不是通过 ajax.
我想在名为 app/FosUserBundle/views/Registration/register.html.twig
的文件中使用 ajax 提交的表单是:
{% extends "FOSUserBundle::layout.html.twig" %}
{% block fos_user_content %}
{% form_theme form '::themes/register-form-theme.html.twig' %}
{% trans_default_domain 'FOSUserBundle' %}
<div class="container" data-bind="with:registerVm">
<div class="register-box">
<div class="register-logo">
<h1>PhotoShare!</h1>
</div>
<div class="register-box-body">
<p class="login-box-msg">Register a new membership</p>
{{ form_start(form, {'method': 'post', 'action': path('fos_user_registration_register'),'attr':{'data-bind':'formSubmitAjax:\{\'success\':registerComplete\}'}}) }}
{{ form_widget(form) }}
<div class="row">
<div class="col-xs-4">
<input type="submit" class="btn btn-primary btn-block btn-flat" value="{{ 'registration.submit'|trans }}" />
</div>
</div>
{{ form_end(form) }}
</div>
</div>
{% endblock fos_user_content %}
表单需要使用以下 knockout.js 自定义绑定处理程序:
define(['knockout','jquery'],function(ko,$)
{
ko.bindingHandlers.formSubmitAjax={
init: function(element, valueAccessor, allBindingsAccessor)
{
var callbacks=valueAccessor();
var action=$(element).attr('action');
var method=$(element).attr('method');
var dataType=(callbacks && callbacks['type'])?callbacks['type']:'json';//By default use Json
$(element).submit(function(e)
{
e.preventDefault();
var form_data= $(this).serialize();
$.ajax({
'method':method,
'data':form_data,
'url':action,
'beforeSend':function()
{
if(typeof callbacks['beforeSend'] === 'function') callbacks['beforeSend']();
},
'success':function(data,textStatus,jqXHR)
{
if(typeof callbacks['success'] === 'function') callbacks['success'](data,textStatus,jqXHR);
},
'error':function(jqXHR,textStatus,errorThrown)
{
if(typeof callbacks['error'] === 'function') callbacks['error'](jqXHR,textStatus,errorThrown);
},
'complete':function(jqXHR,textStatus)
{
if(typeof callbacks['always'] === 'function') callbacks['always'](jqXHR,textStatus);
}
});
});
}
};
})
此表单通过 pager.js 在此 twig 模板上呈现:
{% extends "base.html.twig" %}
{% set classes=''%}
{% block javascriptsHeader %}
<script src="{{asset('assets/vendor/require.js')}}" data-main="{{path('main_javascript')}}" ></script>
{% endblock %}
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" type="text.css" href="{{ asset('assets/vendor/xeditable/css/bootstrap-editable.css') }}" >
<style>
#message-area{
z-index:9999;
}
.page{
min-height:100%;
min-width:100%;
}
</style>
{% endblock %}
{% block body %}
<div id="message-area"></div>
<div class="hold-transition register-page page" data-bind="page: {id:'register', title:'Register', role:'start', sourceOnShow: '{{ path('fos_user_registration_register') }}', withOnShow:function(a){registerVm.init();},with:registerVm}"></div>
{% endblock %}
扩展了以下基本模板:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/bootstrap/css/bootstrap.css')}}" >
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/adminlte/adminlte.css')}}" >
<link rel="stylesheet" type="text/css" href="{{asset('assets/vendor/adminlte/skin-blue.css')}}" >
{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
{% block javascriptsHeader %}
{% endblock %}
</head>
<body class="{{ classes }}">
{% block body %}
{% endblock body %}
{% block javascriptsFooter %}
{% endblock javascriptsFooter %}
</body>
</html>
所有必需的 javascript 我通过以下 require.js 模板呈现它:
requirejs.config({
baseUrl:'{{asset('assets')}}',
paths:{
'text':'{{ asset('assets/vendor/text') }}',
'knockout':'{{ asset('assets/vendor/knockout') }}',
'pager':"{{asset('assets/vendor/pager')}}",
'bootstrap':"{{asset('assets/vendor/bootstrap/js/bootstrap')}}",
'jquery':"{{asset('assets/vendor/jquery')}}",
'jquery_ui':"{{ asset('assets/vendor/jquery-ui') }}",
'xeditable_bootstrap':"{{ asset('assets/vendor/xeditable/xeditable') }}",
'ko_xeditable':"{{ asset('assets/vendor/knockout/knockout.x-editable') }}",
'jquery-fileupload':"{{ asset('assets/vendor/jquery_fileupload/jquery.fileupload') }}",
'jquery-iframe':"{{ asset('assets/vendor/jquery_fileupload/jquery.iframe-transport') }}",
'jquery-ui-widget':"{{ asset('assets/vendor/jquery_fileupload/jquery.ui.widget') }}",
'masterViewModel':"{{ asset('assets/js/viewModels/masterViewModel') }}",
'registerViewModel':"{{ asset('assets/js/viewModels/registerPageViewModel') }}",
{% block Viewmodels %}
{% endblock %}
'formPost':"{{ asset('assets/js/bindingHandlers/formPost') }}",
'compMessage':"{{ asset('assets/js/components/message/message') }}",
'extBooleanToggle':'assets/js/extenders/booleanToggle',
},
shim:{
'pager': ['jquery', 'knockout'],
'jquery_ui':['jquery'],
'bootstrap':['jquery'],
'xeditable_bootstrap':['jquery-ui','bootstrap'],
'ko_xeditable':['xeditable_bootstrap'],
'jquery-fileupload':['jquery-iframe','jquery-ui-widget'],
'jquery-ui-widget':['jquery_ui'],//Jquery_ui already load jquery
'jquery-iframe':['jquery']
{% block CustomShim %}
{% endblock %}
},
waitSeconds: 200,
});
define(['jquery','knockout','pager','masterViewModel','bootstrap'],function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
knockout 和 pager.js 初始化的主视图模型如下:
define(['knockout','jquery','registerViewModel'],function(ko,$,registervm){
function MasterViewModel()
{
var self=this;
self.registerVm=new registervm(self);
}
return new MasterViewModel();
})
你们知道为什么 formSubmitAjax
没有被调用吗?
您需要确保在调用 ko.applyBindings
之前加载绑定处理程序。像这样:
define(['jquery','knockout','pager','masterViewModel','bootstrap', 'formPost'], function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
我将以下内容放在 require.js shim
部分并且非常有效:
'masterViewModel':['registerViewModel'],
'registerViewModel':['formPost']
结果如下main.js.twig
requirejs.config({
baseUrl:'{{asset('assets')}}',
paths:{
'text':'{{ asset('assets/vendor/text') }}',
'knockout':'{{ asset('assets/vendor/knockout') }}',
'pager':"{{asset('assets/vendor/pager')}}",
'bootstrap':"{{asset('assets/vendor/bootstrap/js/bootstrap')}}",
'jquery':"{{asset('assets/vendor/jquery')}}",
'jquery_ui':"{{ asset('assets/vendor/jquery-ui') }}",
'xeditable_bootstrap':"{{ asset('assets/vendor/xeditable/xeditable') }}",
'ko_xeditable':"{{ asset('assets/vendor/knockout/knockout.x-editable') }}",
'jquery-fileupload':"{{ asset('assets/vendor/jquery_fileupload/jquery.fileupload') }}",
'jquery-iframe':"{{ asset('assets/vendor/jquery_fileupload/jquery.iframe-transport') }}",
'jquery-ui-widget':"{{ asset('assets/vendor/jquery_fileupload/jquery.ui.widget') }}",
'masterViewModel':"{{ asset('assets/js/viewModels/masterViewModel') }}",
'registerViewModel':"{{ asset('assets/js/viewModels/registerPageViewModel') }}",
{% block Viewmodels %}
{% endblock %}
'formPost':"{{ asset('assets/js/bindingHandlers/formPost') }}",
//'debug':"{{ asset('assets/js/bindingHandlers/debug') }}",
'compMessage':"{{ asset('assets/js/components/message/message') }}",
'extBooleanToggle':'assets/js/extenders/booleanToggle',
},
shim:{
'pager': ['jquery', 'knockout'],
'jquery_ui':['jquery'],
'bootstrap':['jquery'],
'xeditable_bootstrap':['jquery-ui','bootstrap'],
'ko_xeditable':['xeditable_bootstrap'],
'jquery-fileupload':['jquery-iframe','jquery-ui-widget'],
'jquery-ui-widget':['jquery_ui'],//Jquery_ui already load jquery
'jquery-iframe':['jquery'],
'masterViewModel':['registerViewModel'],
'registerViewModel':['formPost']
{% block CustomShim %}
{% endblock %}
},
waitSeconds: 200,
});
define(['jquery','knockout','pager','masterViewModel','bootstrap'],function($,ko,pager,masterViewModel)
{
$(document).ready(function(){
pager.extendWithPage(masterViewModel);
ko.applyBindings(masterViewModel);
pager.start();
});
});
工作起来很有魅力!!!