Dynamically updating html.listBox in MVC 1.0? - javascript

The client will choose an item from a dropDown list, this newly selected value will then be used to find assets linked to that selected item, these assets will then be loaded into the listBox.
This sounds simple enough, and I'm aware I could use a partial View but it seems overkill for just updating one component on a form.
Any

I've done this in MVC 1.0 myself. I used an onchange on the first drop down which called an action using the value selected. That action returned a JSON result. The jQuery script which called that action then used the JSON to fill the second drop down list.
Is that enough explanation, or would you like help writing the javascript, the action, or both?
Inside your view:
<%= this.Select("DDLName").Attr("onchange", "NameOfJavascriptFunction();") %>
<%= this.MultiSelect("ListBoxName") %>
The javascript will look like this:
function NameOfJavascriptFunction() {
var ddlValue = $("DDLName").val();
jQuery.ajax({
type: 'GET',
datatype: 'json',
url: '/Controller/Action/' + dValue,
success: updateMultiSelect
});
}
function updateMultiSelect(data, status) {
$("#ListBoxName").html("");
for(var d in data) {
$("<option value=\"" + data[d].Value + "\">" + data[d].Name + "</option>">).appendTo("#ListBoxName");
}
}
Finally, the action is something like this (put this in the controller and action from the first javascript):
public ActionResult Action(int id) //use string if the value of your ddl is not an integer
{
var data = new List<object>();
var result = new JsonResult();
this.SomeLogic.ReturnAnEnumerable(id).ToList().ForEach(foo => data.Add(new { Value = foo.ValueProperty, Name = foo.NameProperty }));
result.Data = data;
return result;
}
Feel free to ask follow up questions if you need any more explanation.

Related

Fix URL to return dropdownlist items with JsonResult - MVC- C#

My js dropdown code:
$(document).ready(function () {
$("#ddDivision").change(function () {
$.get("GetDepartment", { id: $("#ddDivision").val() }, function (data) {
$("#ddDept").empty();
$("#ddDept").append("<option value='Please Select'>Please Select</option>")
$.each(data, function (index, row) {
console.log(row);
$("#ddDept").append("<option value='" + row.Value + "'>" + row.Text + "</option>")
});
});
})
});
The JsonResult that returns the list:
public JsonResult GetDepartment(int id)
{
List<SelectListItem> items = new List<SelectListItem>();
//query to return items
return Json(items, JsonRequestBehavior.AllowGet);
}
The error I get (the dropdown does not populate) but I get this in F12 dev tools:
http://localhost/Home/EditView/GetDepartment?id=2
So the URL is wrong, because its on EditView, it should return GetDepartment list, but it doesnt. How do I fix the URL ?
When I'm on the Index view, it returns the correct URL like Home/GetDepartment - how to fix this when using another view?
Also to mention, I use one controller, HomeController.
There are two ways to fix this problem of urls.
Way 1:
Normally the recommended approach is to use the Url.Action helper method which makes sure to generate the correct url for the specified controller and action like:
$.get('#Url.Action("GetDepartment","Home")', { id: $("#ddDivision").val() }, function (data)
Way 2:
and if the js code is in a separate js file then what we do is use data attributes of html elements like:
<select id="ddlDivision" data-url='#Url.Action("GetDepartment","Home")'>
and then in js what we can do is to use that url from data- attributes like below:
$("#ddDivision").change(function () {
var url = $(this).data("url");
$.get(url , { id: $("#ddDivision").val() }, function (data) {
Hope it gives you idea of either way.

How do I populate a list field in a model from javascript?

I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.

Get Django Item ID In Ajax URL

I have a select box in an item edit page, which i would like to be populated via an Ajax call with the saved values.
<script type="text/javascript">
$(document).ready(function() {
$('#editPrefabLineclassBox').on('change', function() {
var selected = this.value;
$.ajax({
url: '/edit-prefab/,
type: 'POST',
data: {
csrfmiddlewaretoken: '{{ csrf_token }}',
lineclassSelected: selected
},
success: function(data) {
var name, select, option;
select = document.getElementById('editPrefabNameBox');
select.options.length = 0;
for (name in data) {
if (data.hasOwnProperty(name)) {
select.options.add(new Option(data[name], name));
}
}
}
});
});
})
</script>
The url i am using in the call is /edit-prefab/. The problem i am having is, the url of the page in Django is actually /edit-prefab/{{ material_item.id }}, only i am not sure how to pass this id to javascript to use in the Ajax call. With just the /edit-prefab/, the page is not found.
After populating the select with the list of items, i would like to have preselected the saved values of the item being edited. I am sure i could populate everything as needed. Its just the setting up of the url that has me a little confused
I have tried passing the id of the item through the view to the template with JSON.dumps, and then parse the variable in JS to use in the url, but i keep getting an unexpected column error when parsing, as from what i know only a dict can be parsed correctly with JSON.
Is there anyone who could please help with this?
EDIT:
def editprefabitem(request, materialitem_id):
context = dict()
mat_item = MaterialItem.objects.get(id=materialitem_id)
context['itemid'] = json.dumps(mat_item.id)
context['lineclass'] = json.dumps(mat_item.lineclass)
context['itemname'] = json.dumps(mat_item.name)
context['diameter'] = json.dumps(mat_item.diameter)
context['quantity'] = json.dumps(mat_item.quantity)
if request.method == 'POST':
if 'lineclassSelected' in request.POST:
lclass = Lineclass.objects.filter(lineclassname=request.POST['lineclassSelected'])\
.values_list('itemname', flat=True).distinct()
request.session['lineclassselected'] = request.POST['lineclassSelected']
lineclass = valuesquerysettodict(lclass)
return HttpResponse(json.dumps(lineclass), content_type='application/json')
if 'itemSelected' in request.POST:
item = Lineclass.objects.filter(itemname=request.POST['itemSelected'])[0]
diams = Lineclass.objects.filter(itemname=item.itemname).values_list('dn1', flat=True).distinct()
request.session['itemselected'] = request.POST['itemSelected']
diameters = valuesquerysettodict(diams)
return HttpResponse(json.dumps(diameters), content_type='application/json')
if 'diamSelected' in request.POST:
request.session['diameterselected'] = request.POST['diamSelected']
if 'editPrefabQuantityBox' in request.POST:
code = Lineclass.objects.filter(lineclassname=request.session['lineclassselected'])\
.filter(itemname=request.session['itemselected']).filter(dn1=request.session['diameterselected'])[0]\
.code
mat_item.name = request.session['itemselected'],
mat_item.type = 'Prefabrication',
mat_item.lineclass = request.session['lineclassselected'],
mat_item.diameter = request.session['diameterselected'],
mat_item.quantity = request.POST['editPrefabQuantityBox'],
mat_item.workpack = Workpack.objects.get(id=request.session['workpackselected']),
mat_item.code = code,
mat_item.datecreated = datetime.datetime.today(),
mat_item.createdby = request.user.username
mat_item.save()
return HttpResponseRedirect('/prefabs/')
return render_to_response('editprefab.html', context, context_instance=RequestContext(request))
The context['itemid'], context['lineclass'] etc, is where i am grabbing the current values of the item and trying to send them through to the template to be parsed by javascript to set the default values for editing in the select boxes, and provide the items id in the url.
The valuesquerysettodict() function, is a small snippet i found, to convert a Models, values_list into a JSON serializable dict to populate the select based on the parameter that was sent through from Ajax. The reason i am using it, is if i return Lineclass.objects.all(), there are a lot of items in the queryset, with the same name, but different itemcode, so i am using a values_list to try and get unique item names to use with the select.
I am sure i am going wrong somewhere i am just not sure where.
thank you for any help you could give.
So I assume you're making your AJAX call at the click of a submit button. Either way, you can supply the Django variable in the value attribute of any tag and retrieve it like this.
In the value attribute of your submit button, pass the Django ID as such:
<button type="submit" value="{{ material_item.id }}" id="submit-button"></button>
Now, in your AJAX request, you can retrieve the ID and send it with your AJAX request like this:
$(document).ready(function(event){
$(document).on('click', '#submit-button' , function(event){
event.preventDefault();
var pk = $(this).attr('value');
data:{
'id': pk,
}
....
});
});

Modifying Replicated EditorTemplates with Javascript

I have an Editor Template which contains a table row with (among other stuff) a dropdown/combobox to select a currency. This edit template is shown many times on the same View and it's possible for a user to add these rows as many times as he wants.
I want changes on a row's dropdown to reflect in an EditorFor (the currency's rate) on the same row, so I've added a onchange html parameter:
<td>
#*#Html.LabelFor(model => model.Currency)*#
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { onchange = "updateCurrency(this)" })
#Html.ValidationMessageFor(model => model.Currency)
</td>
My javascript function makes an ajax call to retrieve the rate for the selected currency:
function updateCurrency(elem) {
alert("Currency changed!")
$.ajax({
type: "GET",
url: "Currency?code=" + elem.value,
success: function (msg) {
// The Rate field's Id:
var RateId = "#Html.ClientIdFor(model=>model.Rate)" // // Halp, problem is here!
document.getElementById(RateId).value = msg;
}
});
}
My problem is that
var RateId = "#Html.ClientIdFor(model=>model.Rate)"
has that Html helper which is server-side code. So when i view the page's source code, the javascript code is replicated (once for each row) and all the var RateId = "#Html.ClientIdFor(model=>model.Rate)" are pointing to the most recently added column's EditorFor.
Probably my way of attempting to solve the problem is wrong, but how can I get my javascript code to update the desired field (i.e. the field in the same row as the changed dropdown list).
I believe that one of the problems is that I have the javasript on the Editor Template, but how could I access stuff like document.getElementById(RateId).value = msg; if I did it like that?
Thanks in advance :)
Figured it out. Hoping it helps somebody:
In my view:
#Html.DropDownListFor(model => model.Currency, new SelectList(Model.CurrencyList, "Code", "Code"), new { #onchange = "updateCurrency(this, " + #Html.IdFor(m => m.Rate) + ", " + #Html.IdFor(m => m.Amount) + ", " + #Html.IdFor(m => m.Total) + ")" })
In a separate JavaScript file:
function updateCurrency(elem, RateId, AmountId, TotalId) {
var cell = elem.parentNode // to get the <td> where the dropdown was
var index = rowindex(cell) // get the row number
// Request the currency's rate:
$.ajax({
blah blah blah .........
(RateId[index - 1]).value = 'retreived value'; // Set the rate field value.
});
}
Seems to be working so far.

Selecting a value on a dynamically populated dropdown list after the list has been populated

So I have a problem where my code tries to select a value on the dropdown list before the list is populated. Basically it calls a javascript function that does an AJAX post to get the dropdown values from php. Then its supposed to select a value on the list, however it does this before the list is populated, so it doesn't find the value. Any idea on how to fix this?
Heres my code
This is where I get the values for the dropdown list
function getProjects(id, proj_select_class)
{
custID = id.options[id.selectedIndex].value;
$.ajax({
type: "POST",
url: "index.php/home/projectlist",
data: {custID : custID},
dataType: "json",
success:function (result){
var ddl = $(proj_select_class);
ddl.children('option:not(:first)').remove();
for (var key in result) {
if (result.hasOwnProperty(key)) {
ddl.append('<option value=' + key + '>' + result[key] + '</option>');
}
}
}
});
}
And heres where I set the values.
AddNew() adds a new row to my table. This is also inside an ajax call.
for (var row in result) {
AddNew();
client_field = document.getElementById('clients'+id);
project_field = document.getElementById('projects'+id);
client_value = $.trim(result[row].client_id);
project_value = $.trim(result[row].project_id);
//set client
client_field.value = client_value;
getProjects(client_field, project_field, client_value);
project_field.value = project_value;
}
Maybe try using a custom event binding to know when your code should fetch the value from the list. To bind to a custom event, you would do something like:
$(document).bind("listpopulated", function(){ /*find value, call AddNew() */ });
and in your ajax success function trigger the "listpopulated" event like so:
$(document).trigger("listpopulated");
References:
http://api.jquery.com/bind/
http://api.jquery.com/trigger/
Fixed it by waiting til the ajax finished running by doing this
$(document).ajaxComplete(function(){ set_values(result); });
set_values is another function that I just loops through all my results and sets all the dropdown values

Categories