Updating Display based on dropdown - c#

As part of a form, I need to display some data about an object from a dropdown. The user using the field is assigning a student to a section of a class, and will need to see the current count of open/filled seats in the class.
Currently, I am building my class drowndown like this:
#Html.DropDownList("Sections Available", new SelectList(Model.AvailableSections, "Id", "Name"))
and later I want to have a div that lists out the availability like:
Open Slots: #someVariable
Filled Slots: #someOtherVariable
This information is part of my Sections model that belongs to the VM for this page. Those look like:
public class ApproveStudentViewModel
{
public string FriendlyName { get; set; }
public List<Section> AvailableSections { get; set; }
public Guid UserId { get; set; }
}
public class Section
{
public Guid Id {get; set; }
public string Name {get; set; }
public int SpacesRemaining {get; set;}
public int SpacesTaken {get; set;}
}
I have a controller call available for getting the section by Id, but that is as far as I've gotten on figuring this out. I'm very new to using MVC and Razor in particular, and this sort of thing should not be as hard as it is appearing to be.

One way you could do this is by using jQuery if you are open to that.You can then make the jQuery AJAX function create a new Div based on the Section by ID. So changes to your code would be as follows:
#Html.DropDownList("SectionsAvailable", new SelectList(Model.AvailableSections, "Id", "Name"))
<div id="slot-information"></div>
The at the end of your Razor page you need to make sure that you are referencing jQuery
<script src="~/lib/jquery/dist/jquery.js"></script>
Now you can create an AJAX call to your controller function and send the sectionID as a parameter:
<script>
$("#SectionsAvailable").change(function () {
$.ajax({
type: "GET",
contentType: "application/json",
dataType: "json",
url: '#Url.Content("~/")' + "{ControllerName/GetSpaceInfo",
data: { sectionID: $("#SectionsAvailable").val() }, //id of the section taken from the dropdown
success: function (data) {
var items = '';
$.each(data, function (i, row) {
items += "<label> Open Slots: " + row.SpacesRemaining + "</label> <label> Filled Slots: " + row.SpacesTaken + "</label> ";
//To test in your browser console
console.log(row.SpacesTaken);
console.log(row.SpacesRemaining);
});
$("#slot-information").html(items);
},
error: function () {
alert("oops");
}
});
});
Finally in your controller (maybe SectionsController) create the following function to return the JSON object.
// returns a list of space available based on section
[HttpGet]
public ActionResult GetSpaceInfo(int sectionID)
{
List<Section> sect = new List<SSection>();
//Should only return 1 item to the JSON list
sect = _context.Sections.Where(m => m.Id == sectionID).ToList();
return Json(sect);
}
Haven't tested the code but this should do the trick. If it isn't working check the console in your browser.

Related

A 404 not found error in ajax Get request for a class library project

I am making a simple class library project where i make an AJAX Get Request in HTML file to Get Data from server ( returned in a method inside a c# class ) .
HTML script field where the AJAX call :
$( function () {
$('#btnSend').click(function () {
$.ajax({
type: "GET",
url: "./Employee/Getdata",
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
console.log(response);
},
failure: function (jqXHR, textStatus, errorThrown) {
alert("HTTP Status: " + jqXHR.status + "; Error Text: " + jqXHR.responseText); // Display error message
}
})
})
});
C# called class :
using System;
using System.Collections.Generic;
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public List<Employee> GetData()
{
var empList = new List<Employee>()
{
new Employee { ID=1, Name="Hamdi"},
new Employee { ID=2, Name="Tester"}
};
return empList ;
}
}
The problem is that a 404 NOT found error is shown in console tells me the Url is wrong, Although it works fine in MVC project with the same url, in the case this class follows the path: Controllers/HomeController/Employee.cs
I searched a lot but all examples are MVC or webforms projects, which are not my case, What can be the right URL then?
Employee should be a controller and GetData should be an IActionResult.. Aside from that the correct URL in javascript would be:
url: "/Employee/Getdata"
. If you use atribute based routing the url in the controller would be:
[HttpGet(“Employee/Getdata”)]
You can do this if you assume that the parent project will always be an ASP.NET MVC project. But you will need to make some modifications to your class. A good explanation of how ASP.NET finds controller classes is here.
In short, rename the class to EmployeeController and the file to EmployeeController.cs and make it inherit from Controller:
public class EmployeeController : Controller
As long as the parent project has the default routes configured, it should find this controller in the library and route requests to it when a request is made to /Employee/GetData
If you want to change the route, you can use attribute routing, but that also assumes that the main project has enabled attribute routing.
[RoutePrefix("Employee")]
public class EmployeeController : Controller
public int ID { get; set; }
public string Name { get; set; }
[HttpGet("Data")]
public List<Employee> GetData()
{
var empList = new List<Employee>()
{
new Employee { ID=1, Name="Hamdi"},
new Employee { ID=2, Name="Tester"}
};
return empList ;
}
}
That should make it work with /Employee/Data.

Display Values based on dropdown selection MVC

I have a requirement which I need to display details based on drop down selection. These details coming from database. when I click one user all then all the details belong to that user has to be displayed.
Model class
public class TaskDetails
{
public string ProjectID { get; set; }
public string ProjectName { get; set; }
public DateTime StartDate { get; set; }
public DateTime EstimatedDate { get; set; }
public string TaskDescription { get; set; }
}
Controller
List<SelectListItem> query = DE.tblEmployees.Select(c => new SelectListItem
{ Text = c.Name, Value = c.Name }).ToList();
ViewBag.Categories = query;
return View();
View
<div class="dropdown">
#Html.DropDownList("CategoryID", (List<SelectListItem>)ViewBag.Categories, "--User Name--")
</div>
In the View I am loading all the user values inside the drop down. But when admin selects any of the user then all the details of user has to be displayed under a table. Upto here I am perfect but from here got strucked. How to move forward how to show the details of the user based on dropdown selection.
Steps
Create A view Where you can display all details of particular user.
Make Ajax call on user change and fetch specific user details from that use with partial view from controller.
Than append that html result to your html.
As Here
Drop Down Html
<div class="dropdown">
#Html.DropDownList("CategoryID", (List<SelectListItem>)ViewBag.Categories, "--User Name--")
</div>
Ajax
$("#CategoryID").change( function (event) {
var userId = $(this).val();
$.ajax({
url: "#Url.Action("GetUser","Controller")",
data: { id : userId },
type: "Get",
dataType: "html",
success: function (data) {
//Whatever result you have got from your controller with html partial view replace with a specific html.
$("#divPartialView").html( data ); // HTML DOM replace
}
});
});
Controller
public PartialViewResult GetUser(int id /* drop down value */)
{
var model = db.Users.find(id); // This is for example put your code to fetch record.
return PartialView("MyPartialView", model);
}
Create a partial view, which is basically to bind data for user details. For example you created a partial view called, userDetails.cshtml.
Add the model reference inside your partial view like bellow,
#model Your_Project_Name.ModalFolderName.TaskDetails
You need to write the html code inside details partial view to bind data.
Suppose you have a div with id="mydetailsTable" inside your main view, where you want to load the user details data after drop down select.
Then call an ajax method in drop down change event, and get the data and load it inside mydetailsTable div. check my bellow code,
$(".myDropdown").change(function() {
var id = $(this).val();
$.ajax({
type: 'GET',
url: '/ControllerName/GetUserDetails/'+id,
contentType: 'application/html; charset=utf-8',
datatype: 'html',
success: function (data) {
$('#mydetailsTable').html('');
$('#mydetailsTable').html(data);
})
});
See, .myDropdown is my class of drop down. You need to add.
Your Action method will be like this,
public ActionResult GetUserDetails(int userId)
{
//fetch the data by userId and assign in a variable, for ex: myUser
return PartialView("userDetails",myUser);
}
That's it. Hope it helps :)

How to pass data like an anonymous object from Jquery datatable in asp.net mvc

I have a Jquery datatable in my ASP.NET MVC view. The columns are like this :
"columns": [
{ "data": "Vote", "autoWidth": true },
{ "data": "Answer1", "autoWidth": true },
{ "data": "View", "autoWidth": true },
{
"data": "Title", "autoWidth": true,
'render': function (Title)
{
//return '<a href=' + Title + '>' + Title + '</a>';
return '<a href=/Questions/GoForAnswer/?idForAnswer='+ 2+'&title=dfg&question=dfg&view=59&date=08%2F10%2F2016%2023%3A39%3A17&answerNumber=13&vote=113>' + Title + '</a>';
}
}
]
Here in title column, I have hard coded the url that returns bunch of objects.But these objects are dynamic. I want to send these into the query string. Like I used to send them like this :
#Html.ActionLink(item.Title, "GoForAnswer", new { idForAnswer = item.ID, title = item.Title, question = item.Question, view = item.View, date = item.Date, answerNumber = item.Answer1, vote = item.Vote })
How can I send the objects from my Jquery function.
What you can do is you can make a model with the same names as your object example:
public class PeopleObject
{
public string name {get;set;}
public int age {get;set;}
}
then all you have to do is make you jquery object with the same names example:
var uniqueObjectName = [{name:'example1',age:20},{name:'example2',age:30}];
then after that you send the jquery object to you controller with ajax and pass the object as a variable example of ajax:
var uniqueObjectName = [{name:'example1',age:20},{name:'example2',age:30}]; // #1
$.ajax({
type: 'POST',
data: uniqueObjectName , // #2
url: '/Home/SubmitMyData',
//contentType: 'application/json', #3
//dataType: 'json', #2
success: alert('Youhou'),
error: alert('not good')
});
in you controller you receive the object like :
public ActionResult Index(PeopleObject uniqueObjectName )
{
return View();
}
notice the controller parameter name and the jquery variable name is the same...
The controller will automatically map the object to the model
Better construct your query in a different way, instead of passing the url directly to $.ajax, modify it to meet your needs.
So, essentially you store the razor generated URL, from #Html.RouteUrl method, in a JavaScript variable. Then you append the query string.
Because, in this case, the query string contains dynamic values, meaning some might not be listed in every request you need to have them listed in a placeholder variable, and replace values accordingly.
After you done with that, you just append the query string to the base URL and provide it to $.ajax.
Take a look at the following example (I have included a fiddle link to see it in action). I store the #Route.Url generated URL in the url variable. I also have declared all the keys of the model in keys table, as well as defined a placeholder string to replace values accordingly.
In fixPlaceholder method I just replace all the {key}=${placeholder} occurrences with the value of my data object (from there you get your dynamic values) or empty (if the value is not set for that particular property).
Finally, I append the placeholder to the url and pass it to $.ajax. Binding will do its magic on the ASP.NET MVC side, so do not worry about that, just declare your controller's action normally, expecting a complex object, like in this example:
[HttpGet]
public JsonResult GetModelAction(SampleViewModel model) {
// Your code here...
}
For your client code you can have something like this:
function fixPlaceholder (keys, data, placeholder) {
for(var i = 0; i < keys.length; i++) {
placeholder = placeholder.replace(keys[i] + "=${PLACEHOLDER}", keys[i] + "=" + (data[keys[i]] || ""));
}
return placeholder;
}
$(function(){
$("button").on("click", function () {
var keys = ["Title", "Question", "AnswerNumber", "View", "Date", "Vote"];
var data = {Title:"Myitle", Question:"MyQuestion", Vote:"10"};
var placeholder = "?Title=${PLACEHOLDER}&Question=${PLACEHOLDER}&AnswerNumber=${PLACEHOLDER}&View=${PLACEHOLDER}&Date=${PLACEHOLDER}&Vote=${PLACEHOLDER}";
var url = '#Url.RouteUrl(new{ action="GetModelAsJson", controller="Home"})';
placeholder = fixPlaceholder(keys, data, placeholder);
url = url + placeholder;
$.ajax({
url: url,
type: "GET",
contentType: "application/json; charset=utf-8"
}).then(function(resp) {
console.log("Response");
console.log(resp);
});
});
Here is a dotnetfiddle, check it and try to work your way based on that. Hope this helps.
Note
Because you are using values that might not be set in the model in every request, meaning they might be null, you need to pay attention to your back-end model. That said, if you have any properties with types like int, DateTime, etc. you might need to mark them as nullable, in order to avoid hairy situations. Like the model below.
using System;
namespace HelloWorldMvcApp
{
public class SampleViewModel
{
public string Title { get; set; }
public string Question { get; set; }
public int? AnswerNumber { get; set; }
public string View { get; set; }
public DateTime? Date { get; set; }
public string Vote { get; set; }
}
}

Why dosen't this javascript object convert to a C# class object?

I'm working on a little test bed app, where you give the app a note name, sign, and octave, and it spits out the frequency the note should sound at.
I'm having a problem with a JavaScript object that is sent to a server via AJAX. However, it does not map at all to the class on the action.
The sender code is a piece of JavaScript:
$someContainer.on('click', '.raise-pitch', function (e) {
e.preventDefault();
var $line = $(this).parents('.item-line'),
// Cache GUI elements for this line. Not pertinent.
var data = {
'model': {
'NoteName': $noteName.val(),
'Sign': $noteSign.val(),
'Octave': $noteOctave.val()
},
'steps': 1
};
var dataString = JSON.stringify(data);
$.ajax({
type: 'POST',
url: '#Url.Action("AlterPitch", "Home")',
data: dataString,
async: true,
dataType: 'json',
success: function (result) {
// Unimportant things.
}
});
});
In the data object, you can see that I have two things: the model and the steps. The steps determines how far we alter the musical note. I have verified that the values for note name, sign, and octave are making it into the data object. The steps are pre-determined.
The data object, however, maps to a ViewModel on the C# side, which looks like this:
public class NoteViewModel
{
public enum NoteSign
{
Natural,
Sharp,
Flat
}
public string NoteName { get; set; }
public NoteSign Sign { get; set; }
public int Octave { get; set; }
public float Frequency { get; set; }
private static readonly Dictionary<string, float> FrequencyLookup = new Dictionary<string, float>
{
{"C", 16.35f},
{"C#", 17.32f},
{"D", 18.35f},
{"D#", 19.45f},
{"E", 20.60f},
{"F", 21.83f},
{"F#", 23.12f},
{"G", 24.50f},
{"G#", 25.96f},
{"A", 27.50f},
{"A#", 29.14f},
{"B", 30.87f}
};
// Methods...not important for reasons below.
}
...which itself is encapsulated in a unique view model:
public class AlterPitchViewModel
{
public NoteViewModel model;
public int steps;
public NoteViewModel AlterPitch()
{
model.ChangeStep(steps);
return model;
}
}
...or at least it should. I set a break point in my controller method:
[HttpPost]
public ActionResult AlterPitch(AlterPitchViewModel model)
{
return Json(model.AlterPitch(), JsonRequestBehavior.AllowGet);
}
...But the model is null, which leads to a NullReference exception.
the model isn't serializing to an object that gets sent along in this context. Obviously I am still doing something wrong. Question is...what?
This approach has worked for me.
Server Side:
First, create your ViewModel
public class TestViewModel
{
public string Id { get; set; }
public string Description { get; set; }
}
Then, in the Controller:
[HttpPost]
public ActionResult TestingViewModel(TestViewModel udata)
{
// Stuff.
}
Client Side:
function CallTestingViewModel() {
// We create the javascript object based on the
// definition of our C# ViewModel class.
var udata = {
Id: 1,
Description: 'This is a test.'
};
// Calling the C# method via AJAX.
$.when(GenericAjaxCall('Home/TestingViewModel', false, udata)).then(function (result) {
// do stuff
});
}
// Return the AJAX call as a Promise Object
function GenericAjaxCall(controllerUrl, async, clientData) {
return $.ajax({
type: 'POST',
async: async,
url: controllerUrl,
data: JSON.stringify(clientData),
contentType: 'application/json;',
dataType: 'json'
});
}
Hope it helps.
Your HttpPost Method must have one unique parameter which is your ViewModel. My advice: create a viewmodel per post WebMethod.
So here:
public class AlterPitchViewModel
{
public NoteViewModel note { get; set; };
public int Steps { get; set; };
}
And adapt your Javascript accordingly. No need to name your javascript model instance as the parameter in the ASP method -> one object arrives and only one parameter is available so no ambiguity.

De serialising JSON in webmethods

Based on the following code...
A user can come along and add as many 'outgoings' as they like via a separate function. I then add a new 'li' to the DOM and auto generate the txt ID
<ul id="ulOutgoing">
<li>
<label>Outgoing 1</label><input type="text" id="txtOutGoing0">
</li>
<li>
<label>Outgoing 2</label><input type="text" id="txtOutGoing1">
</li>
</ul>
At the end of the users path i need to send all txt values and labels to the server to firstly save to a db then generate a response based on the supplied data.
var OutGoings = {};
$('#ulOutgoing').find('li').each(function () {
var obj = {};
obj.text = $(this).find('label').html();
obj.value = $(this).find('input').val();
OutGoings.OutGoing = obj;
});
var DTO = { 'OutGoings': OutGoings };
function callBack(response) {
//Handel my webmethods response
}
ajaxCall(DTO, 'visualise-my-outgoings.aspx/getPieData', callBack, false);
My web method needs to accept the JSON Object and make it usable so I can loop over the txt value and labels and perform some db interactions and further logic
[WebMethod]
public static string getPieData(OutGoings OutGoings)
{
//Handel the object
}
public struct OutGoings
{
}
So... I have two questions
Am i creating the correct JSON object to push to my web method
How do I deserialise the object in my webmethod and what structure should my 'OutGoings' struct take?
You probably need a collection of OutGoing:
public class OutGoing
{
public string Label { get; set; }
public string Value { get; set; }
}
in your page method:
[WebMethod]
public static string GetPieData(OutGoing[] outGoings)
{
// Handle the object
return "Hello World";
}
and finally the client simply fill this collection by looping through the li elements:
var outGoings = $('#ulOutgoing li').map(function() {
return {
Label: $('label', this).html(),
Value: $('input', this).val()
};
}).toArray();
and then POST it to the page method:
$.ajax({
url: 'visualise-my-outgoings.aspx/GetPieData',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({ outGoings: outGoings }),
success: function(result) {
// TODO : process the results
alert(result.d);
}
});
The JSON.stringify method is what properly serializes the javascript array into a JSON string. It is natively built-in modern browsers. If you need to support legacy browsers you might need to include the json2.js script to your page.
Don't use a struct, use a class. C# will handle the deserialization for you. You want something like:
[WebMethod]
public void getPieData(OutGoings[] outGoings)
{
// loop over array, interact with db
}
public class OutGoings
{
public string Text{ get; set; }
public string Value{ get; set; }
}

Categories