也许我走错了轨道......
设置:
我有一个相当复杂的完整dojofied Web应用程序。这个问题的重要部分是dijit.layout.BorderContainer
的中心区域的长形式,其中包含导航树和其他区域中的一些操作按钮。
我想做什么: 如果用户确实输入了数据并且没有保存,他们应该在他要离开表单时收到警告消息(如果他导航离开,点击“新元素”按钮,......)。为了获得更好的用户体验,我想给出一个模态对话框,其中包含“保存”,“仍然离开”,“取消”选项。 可能的想法是使用表单的onBlur事件,停止所有其他事件(很可能是onClick on some other widget),检查更改,如果有更改,则显示对话框,否则让其他事件继续。 我不想为所有非表单活动元素添加checkChanges方法!
第一次测试我试图阻止事件...
此作品
<div id="formArea" dojoType="dijit.form.Form" encoding="multipart/form-data" action="" class="ContentPane" region="center">
<script type="dojo/connect" event="onBlur" >
alert("I don't think so");
</script>
</div>
...但它很难看,我不能轻易继续
这不是
<div id="formArea" dojoType="dijit.form.Form" encoding="multipart/form-data" action="" class="ContentPane" region="center">
<script type="dojo/connect" event="onBlur" args="e">
console.log("blur"); // ok
e.preventDefault();//event.stopt(e)//return false //<--neither of these
</script>
</div>
问题是,如果我点击表单外部的按钮,onBlur
会触发,但我无法停止按钮上的onClick
。
我知道onBlur
没有提供事件对象 - 所以e.something
无法正常工作......
有没有办法在另一个元素上捕获onClick
?
答案 0 :(得分:2)
onBlur
中的Pause button event listener(s)。
查看实际操作:http://jsfiddle.net/phusick/A5DHf/
您有一些按钮事件侦听器,通过on.pausable(node, event, callback)
而非on()
注册:
var b1Handler = on.pausable(button1Node, "click", function() {
console.log("b1.onClick");
});
var b2Handler = on.pausable(button2Node, "click", function() {
console.log("b2.onClick");
});
将处理程序收集到一个数组中:
var handlersToPause = [b1Handler, b2Handler];
添加onBlur
事件监听器:
on(form, "blur", function(e) {
if (this.isDirty()) {
// if data are not saved, pause button event listeners
handlersToPause.forEach(function(handler) {
handler.pause();
});
// display modal dialog here
}
});
添加例如onFocus
事件监听器恢复按钮事件监听器:
on(form, "focus", function(e) {
handlersToPause.forEach(function(handler) {
handler.resume();
});
});
请注意,handler.pause()
暂停了onclick
听众,而不是活动。 onclick
事件在Event queue
中等待,因此在onblur
的执行时间内无法访问。
我会找出一些更强大的解决方案,但这很快就能回答你的问题。无论如何,请查看dojo/aspect
及其around
advice来调用 checkChanges ,而无需更改所有非表单活动元素。
答案 1 :(得分:1)
只有confirm('question?')
afaik才能将您网页上的事件“死锁”。
我已经做了类似的设置,我点击此处的方式(除非用户在地址栏中输入url并点击输入)是一个弹出对话框,只要点击导航树,将用户发送到新视图。考虑:
----------------------------------------
| Nav 1 | Asset1 ( view controller ) |
| Nav 2 | Asset2 ( hidden ) |
----------------------------------------
导航1是默认的onload视图,加载了资产1,包含“设置页面”表单或类似形式,可以更改。诀窍是,Asset1和Asset2是AbstractAsset的衍生物,而AbstractAsset又是一个简单的ContentPane扩展。
在AbstractAsset中,一个名为isDirty
var Viewcontroller = declare("AbstractAsset", [dijit.ContentPane], {
isDirty: function() { return false; }
});
declare("Asset1", [Viewcontroller], {
startup: function() {
// sets up form
...
// and references inputfields to 'this'
this.inputfields = this.form.getChildren();
// and saves (clones) the state of each field
var self = this;
this.inputfields.forEach(function(inputWidget) {
self.states[inputWidget.id] = inputWidget.get("value");
});
},
isDirty: function() {
var self = this;
var dirty = false;
this.form.getChildren().some(input) {
if(self.states[input.id] != input.get("value")) {
dirty = true;
return false; // breaks .some loop
}
return true;
});
return dirty;
}
})
然后,每个导航点击必须调用当前可见的视图控制器的isDirty函数才能继续。假设用户单击nav-tree(dijit.Tree)行节点 Nav 2 。
var navigation = dojo.declare("NavigationController", [dijit.Tree], {
currentView : null,
onLoad: function() {
// start Asset1 in viewNode by default
this.currentView = new Asset1({ }, this.viewNode);
},
onClick : function() {
if(this.currentView.isDirty()) alert("I Dont Think So");
else {
this.loadFunction(this.model.selection.getSelected());
}
}
});
这是实现on-unload-check的一般想法,你需要通过“主应用程序控制器”挂钩任何onClick事件,以确定应该发生什么。 Check this application用作cms导航控制器,page.js:587用于isDirty示例