admin管理员组文章数量:1293730
When registering a product, the user can customize the URL of it!
As the user goes by typing the Tipo de produto
, Nome
or Link
, the website will show you how will the URL for this product
Full url: .png
Note that the field "Tipo de produto" also modifies the URL!!
For this, I created a helper in KnockoutJS
Code
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 )
The only purpose of this helper is to generate a valid URL and display it in the span .link-exibicao
ViewModel
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
will add an attribute with that name and value. For example, the property Name
will generate the HTML:
<input data-bind="value: Nome, event: { change: function(data) { Link(data.Nome()); }}" id="Nome" name="Nome" type="text" value="">
Url.cshtml
The next step would be to add the markup data-bind="url: Link"
in all fields of type 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
Finally, and most simple step would be to build the form =):
<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>
Problem
Whenever typed simple words like: "my product name" everything works perfectly!
But words like meu prodúto côm açênto
the error below is displayed!
Uncaught Error: Unable to parse bindings.
Message: RangeError: Maximum call stack size exceeded;
Bindings value: value: Link, url: Link
When registering a product, the user can customize the URL of it!
As the user goes by typing the Tipo de produto
, Nome
or Link
, the website will show you how will the URL for this product
Full url: https://i.sstatic/jZg7G.png
Note that the field "Tipo de produto" also modifies the URL!!
For this, I created a helper in KnockoutJS
Code
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 )
The only purpose of this helper is to generate a valid URL and display it in the span .link-exibicao
ViewModel
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
will add an attribute with that name and value. For example, the property Name
will generate the HTML:
<input data-bind="value: Nome, event: { change: function(data) { Link(data.Nome()); }}" id="Nome" name="Nome" type="text" value="">
Url.cshtml
The next step would be to add the markup data-bind="url: Link"
in all fields of type 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
Finally, and most simple step would be to build the form =):
<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>
Problem
Whenever typed simple words like: "my product name" everything works perfectly!
But words like meu prodúto côm açênto
the error below is displayed!
Uncaught Error: Unable to parse bindings.
Message: RangeError: Maximum call stack size exceeded;
Bindings value: value: Link, url: Link
Share
asked Mar 17, 2012 at 13:56
ridermansbridermansb
11.1k28 gold badges121 silver badges231 bronze badges
1 Answer
Reset to default 11Your bindingHandler is causing recursive updates, as you are accessing the value:
link = ko.utils.unwrapObservable(valueAccessor())
and later setting it:
valueAccessor()(link)
If link
ends up being identical to its current value, then the chain would stop (observables don't notify on identical (===) values).
When you pass: meu prodúto côm açênto
It bees: meu-prod%C3%BAto%20c%C3%B4m%20a%C3%A7%C3%AAnto
When setting the observable it re-triggers the same binding. So, it calls encodeURI
again and now it is double-encoded like:
meu-prod%25C3%25BAto%2520c%25C3%25B4m%2520a%25C3%25A7%25C3%25AAnto
The observable is set again and since this value is new it triggers it again (and again and again) until you get the call stack error.
Some options to handle this would be to not write back to the observable and just use the binding to encode the URL.
Otherwise a good choice would be to use a writeable puted observable
to intercept writes to the value and manipulate it in the model.
本文标签: javascriptKnockoutJS RangeError Maximum call stack size exceededStack Overflow
版权声明:本文标题:javascript - KnockoutJS: RangeError: Maximum call stack size exceeded; - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741588380a2386974.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论