andreyakinshin / knockout-mvc Goto Github PK
View Code? Open in Web Editor NEWPower of Knockout.js for ASP.NET MVC
Home Page: http://knockoutmvc.com
Power of Knockout.js for ASP.NET MVC
Home Page: http://knockoutmvc.com
Don't know if this should be regarded as a bug, but if the viewmodel contains two properties with the same name, but in different case, when the modelbinder adds propertynames, this error is thrown.
If this will not be supported, maby a little mer explanatory exception should be thrown, so one knows that it's actually the vm that contains an error, and not the markup (as I thought).
The method KnockoutExpressionConverter.VisitMethodCall(MethodCallExpression)
needs to check if the called method is IKnockoutContext.GetIndex()
, compile it to a lambda, execute it to retrieve the index binding, and return it from the visitor method. This should allow complex binding expressions to support GetIndex()
.
For some reason any computed properties that return bool cause the ko.Initialize() method call to fail. For example this fails:
[Computed]
public bool HasExpirationDate { get { return true; } }
This will cause this call to fail:
@ko.Initialize(Model)
With the following error:
No coercion operator is defined between types 'System.Int32' and 'System.Boolean'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: No coercion operator is defined between types 'System.Int32' and 'System.Boolean'.
Source Error:
Line 7: {
Line 8: @Scripts.Render("~/bundles/scripts/datepicker")
Line 9: @ko.Initialize(Model)
Line 10:
Line 11: <script>
Source File: c:\Development\Projects\Base House Contracting\Dev\Website\Views\TradeReview\Index.cshtml Line: 9
Stack Trace:
[InvalidOperationException: No coercion operator is defined between types 'System.Int32' and 'System.Boolean'.]
System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method) +6156301
DelegateDecompiler.MethodBodyDecompiler.Decompile() +297
DelegateDecompiler.Cache2.GetOrAdd(TKey key, Func
2 func) +247
DelegateDecompiler.DecompileExtensions.Decompile(MethodInfo method) +127
DelegateDecompiler.DecompileExpressionVisitor.Decompile(MethodInfo method, Expression instance, IList1 arguments) +36 PerpetuumSoft.Knockout.KnockoutJsModelBuilder.AddComputedToModel(Type modelType, Object model, String modelName) +321 PerpetuumSoft.Knockout.KnockoutContext
1.GetInitializeData(TModel model, Boolean needBinding) +526
PerpetuumSoft.Knockout.KnockoutContext1.Initialize(TModel model) +14 ASP.<>c__DisplayClass4.<Execute>b__2() in c:\Development\Projects\Base House Contracting\Dev\Website\Views\TradeReview\Index.cshtml:9 System.Web.WebPages.<>c__DisplayClassb.<RenderSection>b__9(TextWriter tw) +289 System.Web.WebPages.WebPageBase.Write(HelperResult result) +89 ASP._Page_Views_Shared__Layout_cshtml.Execute() in c:\Development\Projects\Base House Contracting\Dev\Website\Views\Shared\_Layout.cshtml:74 System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +280 System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +125 System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +196 System.Web.WebPages.WebPageBase.Write(HelperResult result) +89 System.Web.WebPages.WebPageBase.RenderSurrounding(String partialViewName, Action
1 body) +233
System.Web.WebPages.WebPageBase.PopContext() +291
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +380
System.Web.Mvc.<>c__DisplayClass1a.b__17() +33
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) +613 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func
1 continuation) +613
System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) +613 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList
1 filters, ActionResult actionResult) +263
System.Web.Mvc.Async.<>c__DisplayClass25.b__22(IAsyncResult asyncResult) +240
System.Web.Mvc.<>c__DisplayClass1d.b__18(IAsyncResult asyncResult) +28
System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +15
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +15
System.Web.Mvc.<>c__DisplayClass8.b__3(IAsyncResult asyncResult) +42
System.Web.Mvc.Async.<>c__DisplayClass4.b__3(IAsyncResult ar) +15
System.Web.CallHandlerExecutionStep.OnAsyncHandlerCompletion(IAsyncResult ar) +282
View:
@using PerpetuumSoft.Knockout
@model Smev.Astd.DataModel.Context
@{ var ko = Html.CreateKnockoutContext(); }
<fieldset>
<legend>Изменение контекстного справочника</legend>
<br />
@using (var contextDictionary = ko.Foreach(m => m.Dictionaries))
{
@ko.Html.HyperlinkButton("[x]", "RemoveDictFromContext", "ContextDictionaryController", new { dictIndex = contextDictionary.GetIndex() })
<table>
<tr>
<td>Идентификатор:</td>
<td>
@contextDictionary.Html.TextBox(m => m.Name)
</td>
</tr>
<tr>
<td>Отображаемое название:</td>
<td>
@contextDictionary.Html.TextBox(m => m.DisplayName)
</td>
</tr>
</table>
<br />
<div>
<table>
<tr>
<th />
<th>Value</th>
@using (var key = contextDictionary.Foreach(k => k.Keys))
{
<th>
@key.Html.TextBox(k => k)
@ko.Html.HyperlinkButton("[x]", "DeleteKey", "ContextDictionaryController", new { dictIndex = contextDictionary.GetIndex(), keyIndex = key.GetIndex() })
</th>
}
<th>
@ko.Html.HyperlinkButton("[+]", "AddKey", "ContextDictionaryController", new { dictIndex = contextDictionary.GetIndex() })
</th>
</tr>
<tbody>
@using (var row = contextDictionary.Foreach(k => k.Rows))
{
<tr>
<td>
@ko.Html.HyperlinkButton("Удалить строку", "RemoveRow", "ContextDictionaryController", new { dictIndex = contextDictionary.GetIndex(), rowIndex = row.GetIndex() })
</td>
<td>
@row.Html.TextBox(r => r.Value)
</td>
@using (var entry = row.Foreach(e => e.Entryes))
{
<td>
@entry.Html.TextBox(e => e)
</td>
}
</tr>
}
</tbody>
@ko.Html.HyperlinkButton("[+]", "AddRow", "ContextDictionaryController", new { dictIndex = contextDictionary.GetIndex() })
</table>
</div>
<br />
}
@ko.Html.Button("Сохранить", "Save", "ContextDictionaryController").Enable(m => m.Dictionaries.Count > 0)
</fieldset>
@ko.Apply(Model)
Generated HTML(this part):
<fieldset>
<legend>Изменение контекстного справочника</legend>
<br>
<!-- ko foreach: Dictionaries -->
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveDictFromContext?dictIndex='+$index()+'');}" href="#">[x]</a> <table>
<tbody><tr>
<td>Идентификатор:</td>
<td>
<input data-bind="value : Name">
</td>
</tr>
<tr>
<td>Отображаемое название:</td>
<td>
<input data-bind="value : DisplayName">
</td>
</tr>
</tbody></table>
<br>
<div>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/AddRow?dictIndex='+$index()+'');}" href="#">[+]</a><table>
<tbody><tr>
<th>
</th><th>Value</th>
<!-- ko foreach: Keys -->
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<th>
<input data-bind="value : $data">
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/DeleteKey?dictIndex='+$parentContext.$index()+'&keyIndex='+$index()+'');}" href="#">[x]</a>
</th>
<!-- /ko -->
<th>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/AddKey?dictIndex='+$index()+'');}" href="#">[+]</a>
</th>
</tr>
</tbody><tbody>
<!-- ko foreach: Rows -->
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<tr>
<td>
<a data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/RemoveRow?dictIndex='+$parentContext.$index()+'&rowIndex='+$index()+'');}" href="#">Удалить строку</a>
</td>
<td>
<input data-bind="value : Value">
</td>
<!-- ko foreach: Entryes -->
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<td>
<input data-bind="value : $data">
</td>
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>
</table>
</div>
<br>
<!-- /ko -->
<button data-bind="click : function() {executeOnServer(viewModel, '/ContextDictionaryController/Save');},enable : Dictionaries().length>0">Сохранить</button>
</fieldset>
Are there any plans to support MVC 6?
For the following JSON:
{"ParentTitle":"Fred","Belongings":{"Title":"My stuff","Things":[{"Description":"Shoe","Amount":123},{"Description":"Hat","Amount":456}],"Summary":"I have lots"}}
The 'Belongings' object is a nested object (and not an array). The ko.mapping.fromJS(viewModelJs) does not make the Belongings object an observable so it's properties should be accessed as:
Belongings.Title
but the ko.Html.TextBox (and the ForEach functionality) create:
Belongings().Title
This then causes an exception in the call to:
ko.applyBindings(viewModel);
because it can't find Belongings().Title
I've manually created html without the () and the bindings work correctly.
Is it possible to fix do a urgent fix for this problem?
Thanks,
P
Example form to reproduce:
@model WebApplication.Models.DefaultModel
@{
var ko = new KnockoutContext<WebApplication.Models.DefaultModel>(ViewContext);
}
<form>
@ko.Html.TextBox(m => m.Foo)
@ko.Html.Span(m => m.Foo)
<button type="submit">Send</button>
</form>
@ko.Apply(Model)
model:
public class DefaultModel
{
public string Foo { get; set; }
}
action:
[ValidateInput(false)] // turn off XSS protection in ASP.NET
public ActionResult Index(Models.DefaultModel model)
{
Response.AddHeader("X-XSS-Protection", "0"); // turn off XSS protection in browser
return View(model ?? new Models.DefaultModel());
}
Steps to reproduce:
</script><script>alert('XSS');</script><script>
into textboxVulnerable line:
Possible solution:
sb.AppendLine(string.Format("var {0}Js = {1};", ViewModelName, json.Replace("<", "\\u003c")));
Workaround:
@{
var script = ko.Apply(Model).ToString();
var p1 = script.IndexOf('>');
var p2 = script.LastIndexOf('<');
WriteLiteral(script.Substring(0, p1) + script.Substring(p1, p2 - p1).Replace("<", "\\u003c") + script.Substring(p2));
}
Is it possible to add an overload: KnockoutBinding.Custom that accepts an expression?
i.e.
public KnockoutBinding Custom(string name, Expression<Func<TModel, object>> binding)
{
Items.Add(new KnockoutBindingItem<TModel, object> { Name = name, Expression = binding });
return this;
}
It could be useful a binding method to map the following cases:
data-bind="click:doSomethingOnViewModel"
data-bind="click:doSomethingOnViewModel.bind($data, 'parameter1')"
where doSomethingOnViewModel is a model's function.
I have a computed property in my viewmodel like this:
[Computed]
public int PasswordScore
{
get
{
var strongRegex = new Regex("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$");
var mediumRegex =
new Regex("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$");
//var enoughRegex = new Regex("(?=.{6,}).*");
if (NewPassword.Length < 1)
return 0;
if (NewPassword .Length < 6)
return 1;
if (strongRegex.Match(NewPassword).Success)
return 4;
return mediumRegex.Match(NewPassword ).Success ? 3: 1;
}
}
Also I have in my View the following statement:
@ko.Html.Span(m => m.PasswordScore)
I get the error NotSupportedException. This exception happens in VisitMethodCall(MethodCallExpression m).
The state of the variables when reaching that function is:
?m.Method
{System.Text.RegularExpressions.Match Match(System.String)}
[System.Reflection.RuntimeMethodInfo]: {System.Text.RegularExpressions.Match Match(System.String)}
base {System.Reflection.MethodBase}: {System.Text.RegularExpressions.Match Match(System.String)}
MemberType: Method
ReturnParameter: {System.Text.RegularExpressions.Match }
ReturnType: {Name = "Match" FullName = "System.Text.RegularExpressions.Match"}
ReturnTypeCustomAttributes: {System.Text.RegularExpressions.Match }
?m.Object
{HelloWorldModel.expression}
CanReduce: false
DebugView: "KnockoutMvcDemo.Models.HelloWorldModel.expression"
Expression: null
Member: {System.Text.RegularExpressions.Regex expression}
NodeType: MemberAccess
Type: {Name = "Regex" FullName = "System.Text.RegularExpressions.Regex"}
I use JsonIgnore attribute to avoid circular references in Json serialization of entity framework classes. The problem is in KnockoutUtilities.ConvertData method because ignore this attribute when explore properties using reflection. This cause stack overflow exception when explore recursive circular references between entity framework objects.
I was wondering if there was a possibility of lowering the version requirement for jQuery, which is currently 2.1.1 in the knockout-mvc NuGet package. Most applications I write (along with many people in the community) need to support IE8 (unfortunately) in which using jQuery 1.11.2 (or any 1.x release) is the only option. Is there a specific feature of knockout-mvc that requires the newer 2.x jQuery? Is it possible to make the requirement 1.11.2 instead?
I have this computed property
[Computed]
public decimal CostoCalcolato
{
get
{
return Fornitore + Facon + Tessuto + Fodera + Accessori + TrasportoInterno + TrasportoCliente + TrasportoAccessori + Dogana + ImportoFinanziamento + Varie;
}
}
in my model, all properties used in the get method are decimal, the error i get is: NotSupportedException();
In the basecode it comes from VisitMethodCall(MethodCallExpression m) in KnockouExpressionConverter.cs.
The Methodname i get is op_Addition that is not supported.
I'm missing something?
Background Information:
I am trying to pass in the current collection iteration's model value as a parameter to an action method in a controller.
More Details:
While working with a collection, I am iterating over the collection with the following code snippet:
@using (var players = ko.Foreach(x => x.BenchPlayers))
{
<tr>
<td @players.Bind.Text(x => x.Name) class="vert-align"></td>
...
<td class="vert-align">@ko.Html.Button("Put in Game", "PutInGame", "Home", new { player = players.Model }, new { @class = "btn btn-primary" })</td>
</tr>
}
I am attempting to access the current iteration's Model value, but I am unsuccessful. The Model
property appears to just be a new instance of the class it represents.
Is there a way to access the current iteration of the foreach loop, for the purposes of passing it to the routeValues
collection, for use in the action method in the controller? If need be, I can just use a property of the object, rather than the entire object, but I'd rather use the entire object.
For "ForEach" method of "KnockoutContext" class, the use of IEnumerable for the "binding" parameter would be useful to avoid constrain on the ViewModel class.
Is it feasible? Changing the code unit tests in the solution always succeed.
I have read article on asp.net that this fall they will add MVC-based new template that uses Knockout.js.
I would like to know if they will introduce original Knockout.js or the wrapper which you have created?
Link - http://aspnet.codeplex.com/
In a situation, when you want to post data and then redirect to some other action, this is not possible with the auto-generated Button, because it expects the model as a return value.
I ended up using the raw HTML with event hooked on a modified post function that receives url in response and then redirects to that url on success.
But it would be nice to either have the possibility to change the onclick function used in auto-generated Button, or have a different method for creating Button with regirecting.
In method ConvertData, property.SetValue(data, value, null); tries to set value for a readonly property. This doesn't throw an exception on .NET 4.0, but on .NET 4.5 it does.
The obvious solution is checking if you can wtite to the property:
if (property.CanWrite) { property.SetValue(data, value, null); }
This seems to be critical bug, I wonder if anyone else encountered this.
A good idea it's plan NuGet integration.
It would be nice if this bound to Unobtrusive validation easy... Which I was able to add pretty easy off the base htmlHelper.
public static class KnockoutEditorExtensions
{
public static MvcHtmlString KnockoutTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string binding)
{
return html.TextBoxFor(expression, null, new { @data_bind = binding + ", attr: { 'name': '" + html.NameFor(expression) + "_' + $index() }" });
}
public static MvcHtmlString KnockoutValidationMessageFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
return html.ValidationMessageFor(expression, null, new { @data_bind = "attr: { 'data-valmsg-for': '" + html.NameFor(expression) + "_' + $index() }" });
}
}
NODE: Some of the code is referenced from here https://github.com/tathamoddie/KnockoutJS-Demos/issues
It seems that after lazy load runs it stores the value of view model internal to the $.get, so when an action button is called it has no idea what "viewModel" is, so it throws a javascript error.
EX:
a data-bind="click : function() {executeOnServer(viewModel, '/api/Address/322');}"
a data-bind="click : function() {executeOnServer(viewModel, '/api/Address/322');}"
<script type="text/javascript">
$(document).ready(function() {$.ajax({ url: '/api/Address/1', type: 'POST', success: function (data) {
var viewModel = ko.mapping.fromJS(data);
ko.applyBindings(viewModel);
}, error: function (error) { alert('There was an error posting the data to the server: ' + error.responseText); } });
});</script>
Hi.
Thanks for Nice Work.
Do you want build this for ASP.NET MVC 4
Hi I have something similar to http://stackoverflow.com/questions/12172571/redirecting-with-k-mvc
@ko.Html.Button("Commit Order", "CommitOrder", "Cart", null, new { @class = "btn btn-default" })
The debugger gets in the commitorder method in the cartcontroller, but when i return json("redirecturl") it does not work. not returing json and redirecting does not work either,
the thing is that i have a case in my code behind where i calculate to what route i need to redirect. Please let me know if you need to see more code or if my issue is not clear.
Hello,
Found, that IIS fails, when model contains circular references.
It is known issue of Microsoft JavaScript Serializer.
Please change the serializer to Json.Net.
Json.Net is faster and has more predictable behavior and I'm already configured my Model to ignore circular references.
I tried to work with Model, containing Data.
The format I received from server with first request: /Date(1354656075282)/"}
While executing it sends with correct format.
But when it returned back from server side: /Date(-62135596800000)/
I cheched with debugger - on server side the field already lost.
So, it could be a problem somewhere in KnockoutUtilities.ConvertData.
Could somebody reproduce this issue?
BTW, please send to NuGet fresh version of the library :)
Until more support is available for other elements, please add in a ko.Html.Tag("name") to handle creation of any tag.
Instead the package should depend on these libraries
Hello,
when the view is bounded with multiple viewmodels the viewmodel name is not passed to subcontext (with, foreach) so the executeOnServer is perfomed passing the main viewModel, not the specific one.
hi,
first of all let me say that your project is one of the best thing i have ever seen, thanks a lot for it
i have a question about template performance
for example in this example here
http://knockoutmvc.com/Collections
if you add child to Annabelle , the Bertie and charles collection get re rendered again, also Annabelle it self and all items get re rendered, is it not bad from performance point of view ?
thanks in advanced.
Hi, My nuget packagemanager updated the delegatecompiler to the latest 0.8.3, which breaks my knockout mvc.
http://www.nuget.org/packages/DelegateDecompiler/0.6.0
could you make the knockout-mvc require at least 0.6.x or higher?
subj :(
There's a model like that
...
{
List<int> Items...
}
Then when you rendering checkboxes like that
@using(var items = ko.Foreach(m = m.Items)
{
@items.Html.Checkbox(m => m % 2 == 0);
}
you'll get output like that
<input type="checkbox" data-bind="checked : ((parseInt() % parseInt(2)) == 0)"/>
it should be
<input type="checkbox" data-bind="checked : ((parseInt($data) % parseInt(2)) == 0)"/>
So, I have to use it like that:
@using(var items = ko.Foreach(m = m.Items)
{
@items.Html.Checkbox(m => "$data % 2 == 0");
}
It works as expect but it's not grace...
there is no way to add binding values to ko.ServerAction() method
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.