javascript - knockout JS : RangeError: Maximum call stack size exceeded;

标签 javascript mvvm knockout.js asp.net-mvc-4

注册产品时,用户可以自定义产品的URL! 当用户输入 Tipo de produto 时, NomeLink , 该网站将向您展示该产品的 URL 将如何显示

Works

Full url: http://i.stack.imgur.com/jZg7G.png

请注意,字段“Tipo de produto”也会修改 URL!!

为此,我在 KnockoutJS 中创建了一个助手

代码

KnockoutJS

ko.bindingHandlers.url =
    update: (element, valueAccessor, allBindingsAccessor, viewModel) ->
        link = ko.utils.unwrapObservable(valueAccessor())
        if link
            link = link.toLowerCase().trim().replaceAll(" ", "-")
            link = encodeURI(link)
        else
            link = ""
        valueAccessor()(link)
        $(element).nextAll(".link-exibicao").text(link).effect("highlight", { color: "#FDBB30" }, 800 )

这个助手的唯一目的是生成一个有效的 URL 并将其显示在范围 .link-exibicao 中。

View 模型

public class ProdutoViewModel
{
    [AdditionalMetadata("data-bind", "event: { change: function(data) { Link(data.Nome());  }}")]
    public string Nome { get; set; }

    [DataType(DataType.Url)]
    [AdditionalMetadata("Prefixo", "Produto/")]
    public string Link { get; set; }

    [Display(Name = "Descrição")]
    [DataType(DataType.MultilineText)]
    public string Descricao { get; set; }

    public int? Ordem { get; set; }
}

AdditionalMetadata将添加具有该名称和值的属性。例如,属性 Name将生成 HTML:

<input data-bind="value: Nome, event: { change: function(data) { Link(data.Nome());  }}" id="Nome" name="Nome" type="text" value="">

网址.cshtml

下一步是添加标记 data-bind="url: Link"在 URL 类型的所有字段中:

@model string
@{

    var values = ViewData.ModelMetadata.AdditionalValues;
    object objDatabind;
    string data_bind = "";
    if (values.TryGetValue("data-bind", out objDatabind))
    {
        data_bind = objDatabind.ToString();
    }

    var nomeCampo = Html.IdForModel();

    var objPrefixo = values["Prefixo"];
    string prefixo = objPrefixo.ToString();
    string separador = "/";
    if (!string.IsNullOrWhiteSpace(prefixo))
    {
        if (prefixo.EndsWith("/") || prefixo.EndsWith("#"))
        {
            separador = prefixo[prefixo.Length - 1].ToString();
            prefixo = prefixo.Substring(0, prefixo.Length - 1);
        }   
    }
}

@Html.TextBoxFor(p => Model, new { data_bind = "value: " + nomeCampo + ", url: " + nomeCampo + (string.IsNullOrWhiteSpace(data_bind) ? "" : ", " + data_bind) })
@Request.Url.Host/<span class="link-prefixo">@prefixo</span><span class="link-separador">@separador</span><span class="link-exibicao"></span>

ProdutoViewModel.cshtml

最后,也是最简单的一步是构建表单 =):

<div class="editor-label">
    <label>Tipo de produto</label>
</div>
<div class="editor-field">
    <select data-bind="options: Tipos, optionsText: 'Nome', value: TipoSelecionado, optionsCaption: 'Selecione...'"></select>
</div>

<div class="editor-label">
    @Html.LabelFor(p => p.Nome)
</div>
<div class="editor-field">
    @Html.EditorFor(p => p.Nome)
    @Html.ValidationMessageFor(p => p.Nome)
</div>

<div class="editor-label">
    @Html.LabelFor(p => p.Link)
</div>
<div class="editor-field">
    @Html.EditorFor(p => p.Link)
    @Html.ValidationMessageFor(p => p.Link)
</div>

<div class="editor-label">
    @Html.LabelFor(p => p.Descricao)
</div>
<div class="editor-field">
    @Html.EditorFor(p => p.Descricao)
    @Html.ValidationMessageFor(p => p.Descricao)
</div>

<div class="editor-label">
    @Html.LabelFor(p => p.Ordem)
</div>
<div class="editor-field">
    @Html.EditorFor(p => p.Ordem)
    @Html.ValidationMessageFor(p => p.Ordem)
</div>

问题

只要输入简单的单词,例如:“我的产品名称”,一切都会完美无缺!
但是像 meu prodúto côm açênto 这样的词显示以下错误!

Uncaught Error: Unable to parse bindings.
Message: RangeError: Maximum call stack size exceeded;
Bindings value: value: Link, url: Link

最佳答案

当您访问值时,您的 bindingHandler 导致递归更新:

link = ko.utils.unwrapObservable(valueAccessor())

然后设置它:

valueAccessor()(链接)

如果 link 最终与其当前值相同,那么链将停止(可观察对象不会通知相同的 (===) 值)。

当您通过时:meu prodúto côm açênto

它变成:meu-prod%C3%BAto%20c%C3%B4m%20a%C3%A7%C3%AAnto

设置可观察对象时,它会重新触发相同的绑定(bind)。因此,它再次调用 encodeURI,现在它被双重编码为​​:

meu-prod%25C3%25BAto%2520c%25C3%25B4m%2520a%25C3%25A7%25C3%25AAnto

observable 被再次设置,因为这个值是新的,所以它会再次(一次又一次)触发它,直到出现调用堆栈错误。

处理这个问题的一些选项是不写回可观察对象,只使用绑定(bind)来编码 URL。

否则,一个不错的选择是使用一个可写计算可观察对象来拦截对值的写入并在模型中对其进行操作。

关于javascript - knockout JS : RangeError: Maximum call stack size exceeded;,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9750533/

相关文章:

wpf - 在大型项目和 MVVM 中使用 Microsoft(或其他)功能区

c# - DelegateCommand.CanExecute 方法行为不正确

Knockout.js 复杂对象绑定(bind)结果为空 HTML 输出

javascript - 如何在 JavaScript 中检测 SharePoint 2013/2016 身份验证模式

javascript - 在 Phonegap 应用程序中使用 JavaScript 将表单数据保存到本地存储

javascript - 希望从大量 javascript 文件中删除注释

javascript - KO.js foreach 绑定(bind)中的分组结果

javascript - 需要用 MomentJS 显示 AM/PM

c# - 在隐藏代码公开的 ViewModel 上设置子属性的 WPF XAML 语法是什么?

javascript - Knockout.js 将变量添加到代码中