KnockoutJS - index of print iteration as input name
I am trying to create my first KnockoutJS form view combined with Spring MVC binding @ModelAttribute
.
- Data is loaded via Ajax and populated with KnockoutJS
- Data is added via KnockoutJS
- Data is removed on top of Ajax and KnockoutJS
- The data will be saved with a normal POST to the Spring MVC controller.
In order to bind form input to Spring MVC controller, I need an iteration index from KnockoutJS. So I tried the following:
But the values from my database are never linked the way they are when I link them to data-bind='value: key'
. Can you help me with the error?
JSP:
<form:form modelAttribute="configurationHelper" action="/saveConfigurationList.htm" method="POST" id="configuration-form" class="form-inline">
<tbody data-bind="foreach: configurations">
<tr>
<td>
// this is working
<input data-bind='value: key' class="form-control input-sm" type="text"/>
// this is not working
<input data-bind='attr:{value: key, name:configurationHelper.configurations[$index].key' class="form-control input-sm" type="text"/>
</td>
<td>
<a href='#' data-bind='click: $root.removeConfiguration' class="ordinary-tooltip" title='<spring:message code="general.delete"/>'>
<i class="fa fa-lg fa-trash-o "></i>
</a>
</td>
</tr>
</tbody>
</form:form>
ModelView:
function ConfigurationViewModel() {
var self = this;
self.configurations = ko.observableArray([]);
self.loadConfigurations = function() {
$.ajax({
type : "POST",
url : "/loadConfigurationList.htm",
success : function(response) {
var responseArray = JSON.parse(response);
var mappedConfigurations = $.map(responseArray.configurations, function(configuration) {
return new Configuration(configuration);
});
self.configurations(mappedConfigurations);
},
error : function(e) {
alert('Error: ' + e.status);
}
});
}
self.saveConfigurationList = function() {
$("#configuration-form").submit();
}
self.addConfiguration = function() {
self.configurations.push({
id: 0,
key: "",
value: "",
});
};
self.removeConfiguration = function(configuration) {
if(confirm(springMessageGeneralDeleteReally)){
$.ajax({
type : "POST",
url : "/deleteConfiguration.htm",
data: {"configurationId": configuration.id},
success : function(response) {
self.configurations.remove(configuration);
},
error : function(e) {
alert('Error: ' + e.status);
}
});
}
};
}
function Configuration(data) {
this.id = ko.observable(data.id);
this.key = ko.observable(data.key);
this.value = ko.observable(data.value);
}
Summary:
- The knockout should only bind values (AJAX loaded) to the inputs and display the correct input name. (for binding input value to Spring MVC controller)
-
configurationHelper
is a request parameter and shouldn't bother knockout. It is only available for list bindingconfigurationHelper.configurations
to Spring MVC.
The following form is bound to the Spring MVC controller:
<form:form modelAttribute="configurationHelper" action="/leina16/configuration/saveConfigurationList.htm" method="POST" id="configuration-form" class="form-inline">
<form:input path="configurations[0].key" class="form-control input-sm"/>
</form:form>
Now I want to expand inputs with Knockout JS, so I need at least an attribute data-bind
and also foreach: $index
from knockout:
<tbody data-bind="foreach: configurations">
<input data-bind='attr:{value: key, name:"configurations[$index].key}' class="form-control input-sm" type="text"/>
</tbody>
But the above is not tied to a Spring MVC controller method and the values are not populated.
source to share
Decision:
Add quotation marks to the "non-Knockout" elements and use the $ index () function.
<tbody data-bind="foreach: configurations">
<tr>
<td>
<input data-bind='attr:{value: key, name:"configurations["+$index()+"].key"}' class="form-control input-sm" type="text"/>
</td>
</tr>
</tbody>
source to share
You are missing }
and probably getting a message stating that Knockout cannot parse the bindings.
Edit:
'attr:{value: key, name:configurationHelper.configurations[$index].key'
To:
'attr:{value: key, name:configurationHelper.configurations[$index].key}'
Since it is configurationHelper
defined outside of your loop foreach
, you will need to reference it with or : $parent
$root
'attr:{value: key, name:$parent.configurationHelper.configurations[$index].key}'
source to share