【问题标题】:Nitrogen wf:wire() does not work for dynamic contentNitrogen wf:wire() 不适用于动态内容
【发布时间】:2017-08-25 16:01:43
【问题描述】:

我有 2 个模块:

测试2

  • 模块创建 div 元素,按钮 id = wf:temp_id()
  • 将 #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.

【问题讨论】:

    标签: erlang nitrogen


    【解决方案1】:

    很好的问题,需要在氮气文档中得到正确答案。

    简短的回答是,在test2:get_content 中,您应该将wf:wire 替换为wf:defer

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

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

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

    静态请求(或者更确切地说,用氮气的说法,first_request,因为在氮气中,“静态请求”是指纯粹的静态内容,例如请求图像文件或其他内容),这很好。返回静态内容,放入页面,然后将所有关联操作插入模板底部的[[[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 函数求值之后进行接线。

    【讨论】:

    • 非常感谢。它现在正在工作。这真的应该是文档的一部分
    • 你完全正确。 wf:defer 函数在文档中进行了描述,但文档并没有真正说明它们是解决这个特定问题的方法,这无疑是一种只见树木不见森林。
    猜你喜欢
    • 2019-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-08
    相关资源
    最近更新 更多