单击动态创建的元素coffeescript绑定Class方法

时间:2014-05-27 12:03:21

标签: javascript coffeescript bind

我有一个类Text,用于处理从输入生成的文本并使其可自定义。例如,我有一个基于给定颜色数组创建颜色按钮的类,这里是代码:


    # Example of array of colors given to the function
    colors: 
        red : "255, 0, 0"
        blue : "24, 149, 207"
        green : "74, 165, 76"
        grey : "202, 202, 202"
        black : "0, 0, 0"
        yellow : "183, 118, 4"
        white : "255, 255, 255"
        purple : "83, 74, 166"

    # Here is the method that loop through colors, create a button for each of them and bind the on click event
    generateColorButtons: (colors) ->
        colorDiv = $('<div></div>',
            class : 'colors'
        )

        for color, rgb of colors
            button = $("<button></button>",
                class: color
            )

            # itemUniqueId is given to the class when instanciated
            button.on 'click', @txtColor(@itemUniqueId, rgb)
            button.appendTo colorDiv        

        return colorDiv

    # Here is the method that I call on click 
    txtColor: (id, color) ->
        $("#" + id + ' .addedTxt').css "color", "rgb(" + color + ")"

点击任何颜色按钮都会给我出现此错误&#34; 未捕获的TypeError:undefined不是函数 &#34;,我知道这是因为它无法访问它所绑定的类方法,但有没有办法让它工作或我必须将它声明为常规函数?

更新

原来我只需更改一点点我的点击绑定就可以了,这里是生成颜色的新类:


    # Loops through every color variables from the options to create a button for each of them
    generateColorButtons: (colors) ->
        colorDiv = $('<div></div>',
            class : 'colors'
        )

        for color, rgb of colors
            button = $('<button></button>',
                class: color
            )

            # Switched from 'on' to 'bind' and created the param to hold the rgb variable because I had scope problems and instead of calling directly the txtColor function, I created an anonymous function with the fat arrow to then call the txtColor in it.
            button.bind 'click', {param: rgb}, (event) =>
                @txtColor(@itemUniqueId, event.data.param)

            button.appendTo colorDiv


        return colorDiv

1 个答案:

答案 0 :(得分:0)

您已经明白了这一点,但让我解释一下出了什么问题以及为什么您(想)您需要{param: rgb}来电中的button.bind参数。

您的原始代码说:

button.on 'click', @txtColor(@itemUniqueId, rgb)

@txtColor(@itemUniqueId, rgb)是对txtColor方法的调用,当button.on的参数构建时会发生这种情况,即当您调用button.on而不是点击发生。这跟说的一样:

x = @txtColor(@itemUniqueId, rgb)
button.on 'click', x

这显然不是你想要做的。

显而易见的解决方案(可能是您尝试的下一件事)将是这样的:

button.on 'click', =>
    @txtColor(@itemUniqueId, rgb)

当你这样做时,你会发现任何八个按钮上的任何一个按钮都会使用相同的RGB值,而RGB值将是for ... of循环迭代的最后一个。为什么会这样?当你有这样的事情时:

for k, v of obj
    f = -> v
    ...

每个迭代器都会创建一个新函数,并将其保留在f但是(这有点但是)这些函数都不会评估v,直到它们为止调用。所有函数在构建时都会存储对v的引用,v的值在每个迭代器上都会发生变化,但v仍然是同一个变量。结果是,当调用函数时,它们最终都会使用v的相同值,并且该值将是迭代中的最后一个值v

一个例子可能有用。如果你这样做:

fns = for i in [0, 1, 2]
    -> i
for f in fns
    console.log f()

然后你的控制台最终会有三个2Demo

这个问题在(Java | Coffee)脚本中很常见,所以CoffeeScript有一个solution specifically for this situation (end of this section)

  

当使用JavaScript循环生成函数时,通常会插入一个闭包装,以确保循环变量被关闭,并且所有生成的函数不只是共享最终值。 CoffeeScript提供do关键字,它立即调用传递的函数,转发任何参数。

您可以使用do重写您的循环:

for color, rgb of colors
    do (color, rgb) =>
        button = $('<button></button>', class: color)
        button.on 'click', =>
            @txtColor(@itemUniqueId, rgb)
        button.appendTo colorDiv

在评估rgb时强制do进行评估,这样您就不会遇到常见的参考问题。