I have a three-step process that is entirely reliant upon JavaScript and Ajax to load data and animate the process from one step to the next. To further complicate matters, the transition (forward and backward) between steps is animated :-(. As user's progress through the process anchor's appear showing the current step and previous steps. If they click on a previous step, then it takes them back to the previous step.
我有一个完整依赖JavaScript和Ajax的三步流程来加载数据并使流程从一个步骤动画到下一个步骤。更复杂的是,步骤之间的转换(向前和向后)是动画的:-(。当用户通过过程锚点的进度显示当前步骤和前面的步骤时。如果他们点击上一步骤,则将它们带回上一步。
Right now, the entire process (forward and backward) works correctly, if you begin at step 1, but if you jump straight to step 3 then the anchors for step 1 and step 2 also perform the same action as step 3.
现在,如果从步骤1开始,整个过程(向前和向后)都能正常工作,但如果直接跳到步骤3,则步骤1和步骤2的锚点也会执行与步骤3相同的操作。
This is the portion of the code that loops through all of the steps up to the current step that the user would be on and displays each anchor in turn and assigns the appropriate function to the click event:
这是代码的一部分,循环遍历用户所在的当前步骤的所有步骤,并依次显示每个锚点并为click事件分配适当的函数:
for (var i = 0; i < profile.current + 1; i++) {
if ($('step_anchor_' + i).innerHTML.empty()) {
var action = profile.steps[i].action;
var dao_id = profile.steps[i].dao_id;
$('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
$('step_anchor_' + i).observe('click', function(){
pm.loadData(action, dao_id, true);
});
Effect.Appear('step_anchor_' + i, {
duration: 1,
delay: (down_delay++)
});
}
}
I know that problem lies in the way that the action and dao_id parameters are being passed in. I've also tried passing profile.steps[i].action and profile.steps[i].dao_id but in that case both profile and i or at least i are out scope.
我知道问题在于传递action和dao_id参数的方式。我也尝试传递profile.steps [i] .action和profile.steps [i] .dao_id,但在这种情况下,无论是profile还是i或至少我的范围。
How do I make it so that I can assign the parameters for action and dao_id correctly for each step? (If it makes any difference we are using Prototype and Scriptaculous)
我该怎么做才能为每个步骤正确分配action和dao_id的参数? (如果它有任何区别我们正在使用Prototype和Scriptaculous)
2 个解决方案
#1
7
Your closure scope chain is causing your problems. By declaring the handler function inline, you've created a closure. Obviously you did this to take advantage of the loop.
你的闭包范围链正在引发你的问题。通过内联声明处理函数,您已经创建了一个闭包。显然你这样做是为了利用循环。
However, since you have created a closure, you're playing by closure scoping rules. Those rules state that the local variables within the parent function remain active and available as long as the closure exists.
但是,由于您已经创建了一个闭包,因此您将通过闭包范围规则进行游戏。这些规则规定,只要闭包存在,父函数中的局部变量就会保持活动状态并且可用。
You are trying to pass and then use "action" and "dao_id" to your closure, but you are passing references here, not values. So when your closures (handlers) are called they use the value that the reference was last assigned. In your case, the Step 3 handler.
你试图通过然后使用“action”和“dao_id”到你的闭包,但你在这里传递引用,而不是值。因此,当调用闭包(处理程序)时,它们使用上次分配引用的值。在您的情况下,步骤3处理程序。
Closure scoping rules are confusing enough, but you may also be confused by the fact that "action" and "dao_id" are still alive even though the loop block has finished executing. Well, in JavaScript there is no such thing as block scope. Once you declare a variable it is available until the end of the function or until is it deleted. Whichever comes first.
关闭范围规则很容易混淆,但是即使循环块已经完成执行,“action”和“dao_id”仍然存在这一事实也可能会使您感到困惑。好吧,在JavaScript中没有块范围这样的东西。声明变量后,它将一直可用,直到函数结束或直到删除为止。以先到者为准。
All that said, you need to break the scope chain. Here are two ways to do that:
总而言之,你需要打破范围链。这有两种方法:
Try this:
for (var i = 0; i < profile.current + 1; i++) {
if ($('step_anchor_' + i).innerHTML.empty()) {
var action = profile.steps[i].action;
var dao_id = profile.steps[i].dao_id;
$('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
$('step_anchor_' + i).observe('click', function(a, b){
return function(){pm.loadData(a, b, true)};
}(action, dao_id));
Effect.Appear('step_anchor_' + i, {
duration: 1,
delay: (down_delay++)
});
}
}
Or this:
function createHandler(action, dao_id) {
return function(){pm.loadData(action, dao_id, true);};
}
/* snip - inside some other function */
for (var i = 0; i < profile.current + 1; i++) {
if ($('step_anchor_' + i).innerHTML.empty()) {
var action = profile.steps[i].action;
var dao_id = profile.steps[i].dao_id;
$('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
$('step_anchor_' + i).observe('click', createHandler(action, dao_id));
Effect.Appear('step_anchor_' + i, {
duration: 1,
delay: (down_delay++)
});
}
}
#2
0
First, remember your execution scope in the click event. The this keyword in that context refers to the element being clicked on. Is there any way you can determine the dao_id from the element that is clicked on?
首先,记住click事件中的执行范围。该上下文中的this关键字指的是被单击的元素。有没有办法可以从点击的元素中确定dao_id?
#1
7
Your closure scope chain is causing your problems. By declaring the handler function inline, you've created a closure. Obviously you did this to take advantage of the loop.
你的闭包范围链正在引发你的问题。通过内联声明处理函数,您已经创建了一个闭包。显然你这样做是为了利用循环。
However, since you have created a closure, you're playing by closure scoping rules. Those rules state that the local variables within the parent function remain active and available as long as the closure exists.
但是,由于您已经创建了一个闭包,因此您将通过闭包范围规则进行游戏。这些规则规定,只要闭包存在,父函数中的局部变量就会保持活动状态并且可用。
You are trying to pass and then use "action" and "dao_id" to your closure, but you are passing references here, not values. So when your closures (handlers) are called they use the value that the reference was last assigned. In your case, the Step 3 handler.
你试图通过然后使用“action”和“dao_id”到你的闭包,但你在这里传递引用,而不是值。因此,当调用闭包(处理程序)时,它们使用上次分配引用的值。在您的情况下,步骤3处理程序。
Closure scoping rules are confusing enough, but you may also be confused by the fact that "action" and "dao_id" are still alive even though the loop block has finished executing. Well, in JavaScript there is no such thing as block scope. Once you declare a variable it is available until the end of the function or until is it deleted. Whichever comes first.
关闭范围规则很容易混淆,但是即使循环块已经完成执行,“action”和“dao_id”仍然存在这一事实也可能会使您感到困惑。好吧,在JavaScript中没有块范围这样的东西。声明变量后,它将一直可用,直到函数结束或直到删除为止。以先到者为准。
All that said, you need to break the scope chain. Here are two ways to do that:
总而言之,你需要打破范围链。这有两种方法:
Try this:
for (var i = 0; i < profile.current + 1; i++) {
if ($('step_anchor_' + i).innerHTML.empty()) {
var action = profile.steps[i].action;
var dao_id = profile.steps[i].dao_id;
$('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
$('step_anchor_' + i).observe('click', function(a, b){
return function(){pm.loadData(a, b, true)};
}(action, dao_id));
Effect.Appear('step_anchor_' + i, {
duration: 1,
delay: (down_delay++)
});
}
}
Or this:
function createHandler(action, dao_id) {
return function(){pm.loadData(action, dao_id, true);};
}
/* snip - inside some other function */
for (var i = 0; i < profile.current + 1; i++) {
if ($('step_anchor_' + i).innerHTML.empty()) {
var action = profile.steps[i].action;
var dao_id = profile.steps[i].dao_id;
$('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
$('step_anchor_' + i).observe('click', createHandler(action, dao_id));
Effect.Appear('step_anchor_' + i, {
duration: 1,
delay: (down_delay++)
});
}
}
#2
0
First, remember your execution scope in the click event. The this keyword in that context refers to the element being clicked on. Is there any way you can determine the dao_id from the element that is clicked on?
首先,记住click事件中的执行范围。该上下文中的this关键字指的是被单击的元素。有没有办法可以从点击的元素中确定dao_id?