I am using the jqAutocomplete plugin which I want to use inside a row of a table.
I cannot get it to work. The autocomplete selection labels do not appear. It only allows me to enter 1 letter.
I am using knockout mapping to map server side viewmodels to client side viewmodels.
The page renders fine. For a new form - as in this case - the code produces 10 empty Lines (not show). I want to use autocomplete to select a contract from a list for the JobName column.
I have copied the viewmodals here, reduced to make it easier to follow;
Parent viewmodel:
public class WholeViewModel : BaseViewModel
{
public WholeViewModel(int employeeId, string name;)
: base()
{
this.Lines = new List<LineViewModel>();
this.Contracts = SessionObjectsSTAS.GetContracts().Select(x => new ContractViewModel { ContractId = x.ContractId, JobName = x.JobName, Label = x.ToString() }).ToList();
this.EmployeeId = employeeId;
this.Name = name;
}
public int EmployeeId { get; set; }
public string Name { get; set; }
public List<ContractViewModel> Contracts { get; set; }
}
The Lines Collection is made up of this viewmodal:
public class LineViewModel
{
public LineViewModel()
{
}
public LineViewModel(int key)
: this()
{
this.Id = key;
this.JobName = string.Empty;
this.Description = string.Empty;
}
public int Id { get; set; }
public int? ContractId { get; set; }
public string JobName { get; set; }
public string Description { get; set; }
}
The ContractViewModel:
public class ContractViewModel
{
public int ContractId { get; set; }
public string JobName { get; set; }
public string Label { get; set; }
}
So to my javascript:
var lineMapping = {
'Lines': {
key: function (line) {
return ko.unwrap(line.Id);
},
create: function (options) {
return new LineViewModel(options.data);
}
}
};
LineViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, lineMapping, self);
};
WholeViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, lineMapping, self);
};
and my ASP.Net Razor page:
@using Newtonsoft.Json
@model ViewModel.WholeViewModel
@{
var data = JsonConvert.SerializeObject(Model);
}
<table class="table">
<tbody data-bind="foreach: Lines">
<tr>
<td>
<input type="text"
data-bind="jqAuto: { source: $parent.Contracts, value: JobName, labelProp: 'Label', inputProp: 'Label', valueProp: 'ContractId' }" />
</td>
<td>
<input type="text" data-bind="value: Description" />
</td>
</tr>
</tbody>
</table>
@section scripts
{
@Scripts.Render("~/bundles/BootstrapJs")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/bundles/inputmask")
@Scripts.Render("~/bundles/Knockout")
<script type="text/javascript">
var wholeViewModel = new WholeViewModel(@Html.Raw(data));
ko.applyBindings(wholeViewModel);
</script>
}
When I set a breakpoint in Visual Studio, the LineViewModel looks like this;
Use a global variable data to bind the source directly.
<script type="text/javascript">
var data = @Html.Raw(data);
var wholeViewModel = new WholeViewModel(data);
ko.applyBindings(wholeViewModel);
</script>
There is a small error in mapping the children, lines. Attributing it to the Knockout documentation itself.
var LineViewModel = function(data) {
ko.mapping.fromJS(data, {}, this);
}
Note that the children are mapped to an empty object and not to lineMapping object. These objects are part of LineViewModel which itself gets attached to the Lines array in lineMapping.
The value should be ContractId. source should be data.Contracts.
<input type="text"
data-bind="jqAuto: {
source: data.Contracts,
value: ContractId,
labelProp: 'Label',
inputProp: 'Label',
valueProp: 'ContractId'
}"
/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With