1

我有2个模块:

测试2

  • 模块创建带有按钮 id = wf:temp_id() 的 div 元素
  • 将 #alert{} 事件连接到它。
  • 返回这些 HTML 元素,以便其他模块可以使用它们。

测试

  • 模块使用按钮 myBtn 和回发消息 {btn_clicked,myBtn} 创建页面内容
  • #alert{"myBtn clicked"} 事件,
  • 添加带有 id: id_insert_here 的空 div - 用作动态元素的占位符
  • 调用 test2:get_content("Static"),从模块 test2 添加内容。

然后在事件函数中,它使用 #wf:insert_after 从 test2:get_content("Dynamic") 添加内容。

预期行为:

  1. 用户点击 myBtn,
  2. 出现警报消息“myBtn clicked”
  3. 出现了新元素“动态内容”这部分正在工作。

  4. 用户单击从 test2:get_content/1 函数生成的“静态”部分中的按钮,

  5. 消息“Btn_TEMP1”点击出现。到目前为止,一切都按预期工作。

现在: 6. 用户单击使用 test2:get_content/1 函数生成的“动态”部分中的按钮,并使用 wf:insert_after() 调用添加到页面。

  1. 预期行为:出现单击消息“btn_TEMP2”。

已实现的行为- 什么也没发生。

wf:wire 不工作。

:如何确保 wf:wire() 对使用 wf:insert_XXX 函数添加的元素有效?

%% -*- mode: nitrogen -*-
-module (test).
-compile(export_all).
-include_lib("../deps/nitrogen_core/include/wf.hrl").

main() -> 
    #template { file="./priv/templates/bare.html",
       bindings=[{'PageTitle',<<"Test">>}]}.

title() -> 
    #template{bindings = L} = main(),
    proplists:get_value('PageTitle',L).

body() ->
    Body = [
       #panel{class="w3-panel w3-green",
              body = 
                    [#p{text = "some text"},
                     #button {
                        id=myBtn,
                        text="myBtn",
                        postback={btn_clicked,myBtn}
                    },
                    #panel{id = id_insert_here}
                    ]}
     ],
    wf:wire(myBtn, #event{ type= click, actions = [ #alert{text="MyBtn clicked"} ]}),
    Body,
    Content = test2:get_content("Pre-compiled"),
    Body2 = [Body,Content],
    Body2.

event({btn_clicked,myBtn} = Event) ->
    io:format("Event: ~p",[Event]),
    Content = test2:get_content("Dynamic"),
    wf:insert_after(id_insert_here,Content);

event(Event) ->
    io:format(" Unexpected Event: ~p ",[Event]),
    ok.
%% end of module test

模块测试2:

-module(test2).
-compile(export_all).
-include_lib("../deps/nitrogen_core/include/wf.hrl").

get_content(Title) ->
    MyId = wf:temp_id(),
    BtnText = io_lib:format("Btn_~p",[MyId]),
    Body = [
    #panel{class="w3-panel w3-yellow",
           body = 
                [#p{text = Title},
                 #button {
                    id=MyId,
                    text=BtnText
                    }]
        }],
    Msg = io_lib:format("Btn: ~p clicked",[MyId]),
    wf:wire(MyId, #event{ type= click, actions = [ #alert{text= Msg} ]}),
    Body.
4

1 回答 1

1

很好的问题,一个需要在氮气文档中正确回答的问题。

简短的回答是,在 中test2:get_content,您应该只替换wf:wirewf:defer

它的推理有点长,但它是这样的:

在这两种情况下(静态和动态),当test2:get_content被调用时,它按以下顺序执行以下操作:

  1. 构建一些氮元素并将它们存储在变量中。
  2. 将动作连接到 (1) 中定义的元素之一
  3. 返回之前制作的元素。

静态请求中(或者更确切地说,用氮气的说法, a first_request,因为在 Nitrogen 中,“静态请求”指的是纯粹的静态内容,例如请求图像文件或其他内容),这非常好。返回静态内容并将其放入页面中,然后将任何关联的操作插入到[[[script]]]模板底部的部分中。

然而,在动态请求中,操作的顺序变得很重要。

test2:get_content你定义的函数做同样的事情,但是函数被评估并且内容被返回给wf:insert_after函数,然后将元素插入到 DOM 中。

该错误巧妙地存在于上述段落中,但我将适应整体上下文以使其更加明显。使用动态请求:

  1. wf:insert需要首先评估对_after (或wf:insert_before, 或wf:update, 或wf:replace其中任何一个)的调用test2:get_content。所以评价test2:get_content()
  2. 构建一些氮元素并将它们存储在变量中。
  3. 将动作连接到 (2) 中定义的元素之一
  4. 返回之前制作的元素。
  5. wf:insert_after获取这些返回的元素并将它们连接到页面。

这里发生的情况是,因为wf:insert_after最后有效地发生了wf:wire,所以元素无处可去。也就是说,wf:wire试图附加的元素在 DOM 中还不存在。

就像这样的伪代码:

$('#my_new_element').click(function(){do_something}));
$('#body').insert_bottom("<button id=my_new_element>click</button>");

使用wf:defer代替可确保在函数评估wf:wire进行接线。insert_XXX

于 2017-04-01T11:18:29.030 回答