Populate Multi-select list from Ajax in Knockout - ajax

I have an editable table based off of the Knockoutjs example. I've been trying to populate a multi-select dropdown list from an AJAX call to ASP MVC controller. I've looked through this example, this one, and this one but am still having issues getting it to work.
Here's the html:
<tbody data-bind='foreach: users' class="table-striped">
<tr>
<td><input class='required number form-control' maxlength="9" stringlength="9" data-bind='value: id, uniqueName: true' /></td>
<td><input class='required form-control' data-bind='value: firstName' /></td>
<td><input class='required form-control' data-bind='value: lastName' /></td>
<td>
<select data-bind="options: MAMUserGroupsListOptions, selectedOptions: MAMSelectedGroup">
<!--dropdown list goes here-->
</select>
</td>
<td><a href='#' data-bind='click: $root.removeUser'>Delete</a></td>
</tr>
</tbody>
Here's the javascript for the knockout portion:
var UserModel = function (users) {
var self = this;
self.users = ko.observableArray(users);
//add user
self.addUser = function () {
self.users.push({
id: "",
firstName: "",
lastName: "",
MAMUserGroupsListOptions: "",
MAMUserGroups: ""
});
};
//remove user
self.removeUser = function (user) {
self.users.remove(user);
};
var viewModel = new UserModel([
{
id: ko.observable(""), firstName: ko.observable(""), lastName: ko.observable(""),
MAMUserGroupsListOptions: ko.observable(),//this is where I need to populate
MAMSelectedGroups: ko.observable(),//this is the result of the multiselect
}
]);
ko.applyBindings(viewModel);
Here's the controller:
[HttpGet]
public ActionResult MAMUserGroupsList()
{
var MAMUserGroupsListOptions = db.MAMUserGroupsListModels.Select(x => new {
MAMUserGroupName = x.MAMUserGroupName
}).ToList();
return Json(MAMUserGroupsListOptions, JsonRequestBehavior.AllowGet);
}
When the controller is called via AJAX, this is what returns:
{MAMUserGroupName: "MAMGroup1"}, {MAMUserGroupName: "MAMGroup2"}, etc...
I'm trying to get the multi-select dropdown to have "MAMGroup1", MAMGroup2, etc.
I've been banging my head against the wall on this- any help would be much appreciated.

Looks like you just want to map the array of objects to extract the one value of interest. If you start with your result in a variable named ajaxResult,
MAMUserGroupsListOptions(ajaxResult.map(obj => obj.MAMUserGroupName));
will assign the values to your observable array. Or if the value is available to you when you're creating your viewmodel,
MAMUserGroupsListOptions: ko.observable(ajaxResult.map(obj => obj.MAMUserGroupName))

Related

popup a dialog and submit partial view in asp.net mvc

So what I am trying to do here is that in the View,
when I click on the button, I want to pass some values generated from the foreach loop (in my case Country and City) to the javascript function.
Inside that javascript function, I want to open up a dialog(partial view) by passing those values (countryName, cityName) to the controller.
Hence in my controller, it will pass those values to the partial view which will be appeared as a dialog and can submit the form.
I've tried with the version without the pop-up dialog (it worked), but having a hard time doing it with a dialog. #3 works btw, but I think I am having a trouble with #1 and #2. Any help would be appreciated. Thanks.
View:
#model IEnumerable<test.Models.Employee>
<table class="table">
<tr>
<th>Country</th>
<th>City</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Country)
</td>
<td>
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
<button onclick="OpenDialog(item.Country, item.City)">
Open Dialog
</button>
</td>
</tr>
}
</table>
<div id="dialog"></div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery-ui-1.12.0.js"></script>
<script>
function OpenDialog(countryName, cityName) {
$('#dialog').dialog({
autoOpen: true,
width: 400,
resizable: false,
title: 'My Table',
modal: true,
open: function(event, ui) {
$(this).load('#Url.Action("getEmployee", "Employee", new
{
country = countryName,
city = cityName
})');
},
buttons: {
"Close": function () {
$(this).dialog("close");
}
}
});
}
</script>
}
Controller:
public ActionResult getEmployee(string country, string city)
{
var viewModel = new EmployeeViewModel()
{
Country = country,
City = city
};
return PartialView("EmployeeDialog", viewModel);
}
Partial View:
#model test.ViewModels.EmployeeViewModel
#using (Html.BeginForm("PostEmployee", "Employee", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(model => model.Country)
#Html.HiddenFor(model => model.City)
#Html.EditorFor(model => model.Comments)
<input type="submit" value="Submit"/>
}
#Url.Action() is razor code and is parsed in the server before its sent to the view. countryName and cityName are javascript variables and do not even exist at that point (they are not in scope). Change the code in the OpenDialog() function to
var url = '#Url.Action("getEmployee", "Employee")';
var data = { country: countryName, city: cityName };
$(this).load(url, data);
As a side note, there is really no need to be calling the server each time to return values that you already have in the view. You could just render the form in the dialog initially (for a default EmployeeViewModel and then in the OpenDialog just set the values of the inputs for properties Country and City, for example $('#Country').val(countryName);

How to load custom content to jquery dialog from html table

I have a list of images presented in a table format with an update option to edit the image/description in a dialog box.
I have implemented a javascript function loadDialog to dynamically pass the id to the dialog.
However, the editor complains that id is not recognized in the line below:
$(this).load("#Url.Action("UpdateProjectImageDetail", new { ProjectId = id})") ;
Following are the script and html files.
$(function(){
$('#OpenImgDialog').dialog({
autoOpen: false,
width: 400,
resizable: false,
title: 'Add/Update Image',
modal: true,
buttons: {
"Cancel": function () {
$(this).dialog("close");
}
}
});
});
function loadDialog(id) {
var Pid = id;
$("#OpenImgDialog").dialog({
open: function (event, ui) {
var Pid = id;
$(this).load("#Url.Action("UpdateProjectImageDetail", new { ProjectId = id})") ;
}
});
$('#OpenImgDialog').dialog('open');
}
Here is my HTML
<table>
<tr>
<th>
Image
</th>
<th>
Description
</th>
<th></th>
</tr>
#foreach (var item in Model.Images) {
<tr>
<td>
<img src ="#item.ImageString" width="200" height="100" />
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
<td>
<a class="UpdateImage" href="#" onclick="loadDialog(#item.Id)">Edit</a>
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
How can I pass arguments from javascript to Url.Action?
Or is there a better approach to solving this problem?
Any demo/reference/solution will be helpful for me.
Thanks in advance!
Appologies I think I know what you are after.
in the
$(this).load("#Url.Action("UpdateProjectImageDetail", new { ProjectId = id})") ;
the
#Url.Action("UpdateProjectImageDetail", new { ProjectId = id})
is running server side you need to pass in the id from the client to the server. which meands it should look something like this
function loadDialog(id) {
var Pid = id;
$("#OpenImgDialog").dialog({
open: function (event, ui) {
var Pid = id;
var url = '#Url.Action("UpdateProjectImageDetail")?ProjectId=' + id;
$(this).load(url) ;
}
});
$('#OpenImgDialog').dialog('open');
}
#Url.Action() is server side code, so you can't pass a client side (js) variable to it.
Without looking too closely, you could probably do something like:
$(this).load("#Url.Action(...)" + "?ProjectId=" + id);
There's probably a more elegant solution, but that's all I have time for right now... ;)

Updating TextBoxFor when changing DropDownListFor

I'm using ASP MVC 3 and currently having a problem getting new data in my textboxes when I change the value of my dropdownlistfor.
<div id="BagelProductEdit">
<h2>Bagel</h2>
#Html.DropDownListFor(x => x.SelectedOptionBagel, Model.LstBagelsList, new { #class = "width200", #onchange = "refreshTextBoxFors()" })
<br />
<table>
<tr>
<td>Bagelnaam</td><td> #Html.TextBoxFor(x => x.LstBagels.ElementAt(x.SelectedOptionBagel).Name,new { Name ="txtEditBagelName" })</td>
</tr>
<tr>
<td>Vertaling</td><td> #Html.TextBoxFor(x => x.LstBagels.ElementAt(x.SelectedOptionBagel).NameFr,new { Name ="txtEditBagelNameFr" })</td>
</tr>
<tr>
<td>Prijs</td>
<td> #Html.TextBoxFor(x => x.LstBagels.ElementAt(x.SelectedOptionBagel).Price,new { Name ="txtEditBagelPrice" })</td>
</tr>
</table>
<input class="button widthorderProduct" type="submit" name="BtnEditBagel" value="Edit een bagel" />
</div>
How can I get the refreshed value in my textboxes when the value of my dropdownlist changes?
You can add an ID to that dropdownlist:
#Html.DropDownListFor(x => x.SelectedOptionBagel, Model.LstBagelsList, new { #class = "width200", #onchange = "refreshTextBoxFors()", id= "myDDL" })
Then, in the refreshTextBoxFors() you can access the dropdownlist selected value this way (assuming you are using jQuery):
$("#myDDL").val();
If you need the selected text (not the value):
$("#myDDL :selected").text();
In you are not using jQuery, but plain Javascript, you can use this for getting the selected value in a DropDownList:
var e = document.getElementById("myDDL");
var selValue = e.options[e.selectedIndex].value;
EDIT - To set the data of textboxes:
Once you have the DDL selected value you can do:
if(selValue == '1'){
$('#test').val('here is the value you want to put');
}
else{
$('#test').val('other value');
}
Now, in the example in your comment, it seems you have a list of TextBoxFors. So if you put an id in a loop, it will set that to all of your textboxes. You can put a #class = "test" instead and access the textboxes using $('.test') instead of $('#test').

binding new DOM elements to viewmodel after AJAX call

I'm having troubles binding new DOM elements to my viewmodel. This elements are in a partial view loaded using an AJAX call (see the customizeQuote function below).
$(function () {
var mvcModel = ko.mapping.fromJS(initialData);
function QuoteViewModel() {
var self = this;
self.customizeQuote = function (quote) {
self.selectedQuote = quote;
//remove the disable attribute on all form controls before serializing data
$(".step").each(function () {
$(this).find('input, select').removeAttr('disabled');
});
//convert form data to an object
var formData = $('#etape').toObject();
$.ajax("getSelectedQuote", {
data: ko.toJSON({ model: self.selectedQuote, model1: formData }),
type: "post", contentType: "application/json",
success: function (result) {
$("#custom").html(result);
$("#etape").formwizard("show", "customize");
ko.applyBindings(self.selectedQuote, $("#covers"));
}
});
}
}
var myViewModel = new QuoteViewModel();
var g = ko.mapping.fromJS(myViewModel, mvcModel);
ko.applyBindings(g);
});
Here's the partial view html:
#model QuoteViewModel
<table id="covers">
<thead>
<tr>
<th>
ProductName
</th>
</tr>
</thead>
<tbody data-bind="foreach: CoverQuotesViewModel">
<tr>
<td>
<input data-bind="value: ProductName" />
</td>
</tr>
</tbody>
</table>
the line:
ko.applyBindings(self.selectedQuote, $("#covers"));
triggers an error:
"ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"
I'm fairly new to knockout and I don't see what I'm doing wrong. Any idea ?
$("#covers") is not a DOM node though, it is an jQuery object. Perhaps try using this instead:
ko.applyBindings(self.selectedQuote, $("#covers")[0]);
The [0] will get the first matched element of the selector in the jquery object.

MVC3 unobtrusive validators not being written into partial page

When the following code is retrieved via an ajax call no validators are written into the view. Any number of these partial views might be added to the page and the textbox gets a datepicker, so that's why the unique id is generated. I certainly appreciate any help.vie
#using Nautilus.Core.Model.Enumeration
#using Nautilus.Web.Models
#using Nautilus.Web.Views.Tools
#model IntensityHistoryModel
<tr>
<td class='removeIntensityScore' title='Click to remove this item.'></td>
<td>
<span></span>
</td>
<td>
#Html.ValidationMessageFor(m => m.IntensityDateGUID)
#Html.TextBoxFor(m => m.IntensityDate, new { id = Model.IntensityDateGUID, #class = "intensityScoreDate", style = "width:120px" })
</td>
<td>
#Html.DropDownList("IntensityScore", ViewHelper.GetSelectListWithDescriptionFromEnum<IntensityScore.Values>("", new[] { "0" }), " -- Select -- ", new { style = "width:150px;margin:0" })
</td>
</tr>
When you do the ajax call, in the callback function you have to call again the validation.
Something like that
$("#myDiv").load($("#myA").attr("href"), function () {
$.validator.unobtrusive.parse("#myFormPartial");
});
It's not including the validation data attributes because the elements are not in a form. The workaround is to initialize a FormContext for your partial view:
#{
ViewContext.FormContext = new FormContext();
}
<tr><!-- your partial content --></tr>

Resources