I am using c# and ASP.NET MVC4 for a web application (with mobile template).
I'm having a problem with my Details view page. (First you select something from Index page and then it goes to Details page) I have put a bing map on the page and the map doesn't load.
First I thought it was something wrong with the map but its not.
I noticed that the url is
http://localhost:2550/Place/Details
of the page. However if I manually put a '1' on the end like so http://localhost:2550/Place/Details/1
then the map loads on the page. I don't understand why this is...
does anyone know why? thanks
my view page for Details:
#model Project.Models.Place
#{ ViewBag.Title = "Details";}
<h2>Place Details</h2>
<fieldset>
<div class="display-label"> Name: #Model.Name</div>
<div class="display-label">Address: #Model.Address</div>
<div class="display-label">Post Code: #Model.PostCode</div>
<div class="display-label"> PhoneNo: #Model.PhoneNo</div>
</fieldset>
<p> #Html.ActionLink("Back to List", "Index")</p>
<body onload="getMap();">
<div id='myMap' style="position:relative; width:400px; height:400px;"></div>
<div>
<input type="button" value="createWalkingRoute" onclick="createDirections();" />
</div>
<div id='directionsItinerary'> </div>
</body>
#section scripts{
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map = null;
var directionsManager;
var directionsErrorEventObj;
var directionsUpdatedEventObj;
function getMap() {
map = new Microsoft.Maps.Map(document.getElementById('myMap'), { credentials: 'mykey' });
}
function createDirectionsManager() {
var displayMessage;
if (!directionsManager) {
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
displayMessage = 'Directions Module loaded\n';
displayMessage += 'Directions Manager loaded';
}
alert(displayMessage);
directionsManager.resetDirections();
directionsErrorEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', function (arg) { alert(arg.message) });
directionsUpdatedEventObj = Microsoft.Maps.Events.addHandler(directionsManager, 'directionsUpdated', function () { alert('Directions updated') });
}
function createWalkingRoute() {
if (!directionsManager) { createDirectionsManager(); }
directionsManager.resetDirections();
// Set Route Mode to walking
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.walking });
var seattleWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Seattle, WA' });
directionsManager.addWaypoint(seattleWaypoint);
var redmondWaypoint = new Microsoft.Maps.Directions.Waypoint({ address: 'Redmond, WA', location: new Microsoft.Maps.Location(47.678561, -122.130993) });
directionsManager.addWaypoint(redmondWaypoint);
// Set the element in which the itinerary will be rendered
directionsManager.setRenderOptions({ itineraryContainer: document.getElementById('directionsItinerary') });
alert('Calculating directions...');
directionsManager.calculateDirections();
}
function createDirections() {
if (!directionsManager) {
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: createWalkingRoute });
}
else {
createWalkingRoute();
}
}
</script>
}
my controller action for Details:
public ViewResult Details(int id)
{
ViewBag.events = eventRepository.PlaceEvents(id);
return View(placeRepository.Find(id));
}
Possible cause, may be you haven't written Controller default controller with Zero arguments.
Or you haven't written controller with [HttpPost] attribute
Will be easy if you put code for the controller here.
If you say that the navigation with /1 at the end works but your current url is without the number, your url on the index page is wrong.
Your url is now something like
#Html.ActionLink("Details", "Place")
Change it to something like this:
#Html.ActionLink("Details", "Place", new { id = #Model.Id })
So the problem is that your id isn't given to your details action.
Related
I started learning AJAX like this week and I was trying to make a simple voting thingy on page in asp mvc - when you click one button you get message like a popup (in browser) and count increments, when you click second, you get another count decrements, you get the idea.
I wanted to test it's possible to do like voting system (upvotes/downvotes) that will update itself's oount on click without needing to refresh the page.
However, when I click on this buttons, it gets me blank page with the things that return json contains. (picture included at the very bottom of post).
I am most likely missing something obvious, so please bear with me and if you could navigate me where am I wrong, please do.
My Controller:
public IActionResult Privacy()
{
Vote vote = new Vote();
vote.Votes = 0;
return View(vote);
}
[HttpPost]
public ActionResult VoteUp(string plus, string minus)
{
Vote vote = new Vote();
if (plus == null)
{
vote.Votes = vote.Votes -1;
var message = "You voted down";
return Json(new { success = true, message = message }, new Newtonsoft.Json.JsonSerializerSettings());
}
else if ((minus == null))
{
vote.Votes = vote.Votes +1 ;
var messagez = "You voted up";
return Json(new { success = true, message = messagez }, new Newtonsoft.Json.JsonSerializerSettings());
}
else { }
var messagebad = "STH WENT WRONG";
return Json(new { success = true, message = messagebad }, new Newtonsoft.Json.JsonSerializerSettings());
}
My View:
#model JSON_RETURN.Models.Vote
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = "sssss";
}
<form asp-action="VoteUp" asp-controller="Home" method="POST" data-ajax="true">
<div class="form-group"> </div>
<div class="input-group-button">
<button name="plus" class="btn btn-dark" onclick="" value="1" >+</button>
#Model.Votes
<button name="minus" class="btn btn-dark" onclick="" value="-1" >-</button>
</div>
</form>
#section scripts{
<script src="~/lib/ajax/jquery.unobtrusive-ajax.js"></script>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script type="text/javascript">
function SubmitForm(form) {
form.preventDefault();
$.ajax({
type: "POST",
url: "HomeController/VoteUp", //form.action,
data: ('#form'),
success: function (data) {
if (data.success) {
alert(data.message);
} else {
}
},
});
};
</script>
}
My Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace JSON_RETURN.Models
{
public class Vote
{
public int Votes { get; set; }
}
}
And there's the blank page I'm getting every click (message varies ofc):
(https://imgur.com/uVNSmE6)
What you did is just a form submit instead of using ajax. Why it return json string that is because you return json string in your backend code(return Json(new { success = true, message = messagebad }, new Newtonsoft.Json.JsonSerializerSettings());).
I saw you use jquery.unobtrusive-ajax.js in your code, also you create a js function with ajax. Actually, you just need to choose one of the two ways to achieve your requrement.
Here is the correct way of using jquery.unobtrusive-ajax.js :
Note:
1.If you use asp.net core, it contains jquery.js in _Layout.cshtml by default. So when you use #section Scripts{}, no need add the jquery.js again. If your _Layout.cshtml does not contain jquery.js, you need add this js file before jquery.unobtrusive-ajax.js:
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/ajax/jquery.unobtrusive-ajax.js"></script>
2.You need specific data-ajax-update to tell the elements where need to be updated with the AJAX result.
More supported data attributes for jquery.unobtrusive-ajax.js you can refer to here.
View:
#model Vote
#addTagHelper*, Microsoft.AspNetCore.Mvc.TagHelpers
#{
ViewData["Title"] = "sssss";
}
<div id="result"> //add this div...
//add this...
<form asp-action="VoteUp" asp-controller="Home" method="POST" data-ajax-update="#result" data-ajax="true">
<div class="form-group"> </div>
<div class="input-group-button">
<button name="plus" class="btn btn-dark" value="1">+</button>
#Model.Votes
<input hidden asp-for="Votes" /> //add this....
<button name="minus" class="btn btn-dark" value="-1">-</button>
</div>
</form>
</div>
#section scripts{
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.js" integrity="sha256-v2nySZafnswY87um3ymbg7p9f766IQspC5oqaqZVX2c=" crossorigin="anonymous"></script>
}
Controller:
Note: You can see that I add a hidden input for Votes in form, that is because only input or select type of element can be post to backend. The reason for why I want to get Votes value is because your code always create a new instance for Vote, the value will always plus start with 0.
public IActionResult Privacy()
{
Vote vote = new Vote();
vote.Votes = 0;
return View(vote);
}
[HttpPost]
public ActionResult VoteUp(string plus, string minus)
{
Vote vote = new Vote();
vote.Votes = int.Parse(Request.Form["Votes"]);
if (plus == null)
{
vote.Votes = vote.Votes - 1;
}
else if ((minus == null))
{
vote.Votes = vote.Votes + 1;
}
else { }
return PartialView("Privacy", vote);
}
Result:
This is the way I was sending my model to an angular controller scope.
c# Controller:
public class AreaMenuController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return PartialView("_AreaMenu", mod.ModuleMenus);
}
}
View cshtml:
#using Nuclei.Models
#model IEnumerable<Nuclei.Models.Menu>
<script type="text/javascript">
#{ var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); }
window.areaMenus = #Html.Raw(serializer.Serialize(Model));
</script>
<script type="text/javascript" src="#Url.Content("~/Scripts/AngularControllers/_AreaMenuController.js")"></script>
<div ng-controller="AreaMenuController as vm" ng-init="vm.initializeController()">
<div id="accordion" ng-class="accordian-menu" style="visibility: visible;">
<ul>
<li ng-repeat="menu in vm.areaMenus">
...
</li>
</ul>
</div>
</div>
Angular Js file:
var NucleiApp = angular.module('NucleiApp');
NucleiApp.controller('AreaMenuController', ['$scope', '$http', '$location', function ($scope, $http, $location) {
"use strict";
var vm = this;
vm.initializeController = function () {
vm.areaMenus = window.areaMenus;
}
}]);
Question 1: Is there a smoother way to send your c# model through to angular other than through global window object?
You can use an $http get from angular, however because this is processed client-side there is always a bit of lag before it gets displayed, because it needs to call the c# controller and get the data. So I'm reserving $http get for updates only.
The other other way I was thinking was to send the view a Json object straight off:
c# controller:
public class AreaMenusController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
return PartialView("_AreaMenu", GetAreaMenus());
}
public JsonResult GetAreaMenus()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return Json(new { areaMenus = mod.ModuleMenus }, JsonRequestBehavior.AllowGet);
}
}
View cshtml:
#using System.Web.Mvc
#model JsonResult
<script type="text/javascript">
window.areaMenus = #Model;
</script>
Question 2: I'm not really sure how to initialize the #model at this point and send it through to the angular file and again, if there is a better option than javascripts global window object... open to suggestions!
We currently do this to bootstrap a set of data that is later updated by a call into a WebAPI.
The reason we do this is we have found cases where the data, when bootstrapped via an API call, was coming back too slowly, which gave a bad experience to our users.
In our razor view:
<html>
<head>
<script>
window.areaMenus = '#Html.Raw(Model.SerializedJsonString)';
</script>
</head>
</html>
Then when our angular app is Run(), we deserialize the data, and use it from there:
var app = angular.module('myApp', ["stuff"])
.run(["menuService", (menuService) => {
// deserialize the json string into my object
var areaMenus = angular.fromJson(window.areaMenus);
// do something with it
menuService.Load(areaMenus);
}]);
This'll get the data available to angular immediately without having to wait for a $http request to complete, which should address your issue.
I want to display an autocomplete textbox in a MVC C# View using jQuery-ui autocomplete, this is the code of my view
#{
ViewBag.Title = "Index";
}
<script src ="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<script type="text/javascript">
$(function () {
$("#SearchString").autocomplete({
source: "/Borrar/autocompletar",
minLength: 1,
select: function (event, ui) {
if (ui.item) {
$("#SearchString").val(ui.item.value);
}
}
});
});
</script>
<div class="container col-md-10 col-md-offset-3">
<h2>Autocompletar</h2>
#using (Html.BeginForm())
{
<p>
Empresa: #Html.TextBox("SearchString")
<input type="submit" value="Search" />
</p>
}
</div>
this is the code of the controller that should populate the textbox
public JsonResult autocompletar(string prefix)
{
List<GFC_Site.ViewModels.EmpresaAutocomplete> listado = new List<GFC_Site.ViewModels.EmpresaAutocomplete>();
ProxyGFC.ServiceGFCClient cliente = new ProxyGFC.ServiceGFCClient();
List<WcfService.Entidades.EmpresaAutocomplete> listadoBase = new List<WcfService.Entidades.EmpresaAutocomplete>();
listadoBase = cliente.Autocompletar(prefix);
foreach (var item in listadoBase)
{
GFC_Site.ViewModels.EmpresaAutocomplete dato = new ViewModels.EmpresaAutocomplete();
dato.empresa = item.empresa;
//dato.np = item.np;
listado.Add(dato);
}
return Json(listado, JsonRequestBehavior.AllowGet);
}
where (GFC_Site.ViewModels.EmpresaAutocomplete) is a class with only one string property (empresa) and (ProxyGFC.ServiceGFCClient cliente) is a connection to a WCF Server, the WCF is the one that connects the application with the database and (List listadoBase) is a class in WCF with two properties(empresa and np).
and this is the method in WCF that retrieve the info that I want to display in the textbox
public List<EmpresaAutocomplete> Autocompletar(string prefix)
{
OdbcCommand cmd = Helper.Commandos.CrearComando();
cmd.CommandText = "select numero_patronal, nombre_empresa from empresas where estado= ? and nombre_empresa like ?";
cmd.Parameters.Add("#estado", OdbcType.VarChar).Value = "1";
cmd.Parameters.AddWithValue("#empresa", prefix + "%");
List<EmpresaAutocomplete> data = new List<EmpresaAutocomplete>();
try
{
cmd.Connection.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
EmpresaAutocomplete datos = new EmpresaAutocomplete();
datos.np = reader["numero_patronal"].ToString();
datos.empresa = reader["nombre_empresa"].ToString();
data.Add(datos);
}
}
catch (Exception ex)
{
throw new ApplicationException("Excepcion :", ex);
}
return data;
}
well, my problem is that the textbox doesn´t show anything, actually it gets frozen
could you please tell me what seems for you to be the problem?
First off, let’s take take a look at autocomplete in action, starting with a text input:
<label for=”somevalue”>Some value:</label><input type=”text” id=”somevalue” name=”somevalue”/>
If we add a reference to the jQuery UI script file and css file, we can add a script block to our view:
<script type=”text/javascript” language=”javascript”>
$(document).ready(function () {
$(‘#somevalue’).autocomplete({
source: ‘#Url.Action(“Autocomplete”)’
});
}) </script>
This script block identifies the text input by id and then invokes the autocomplete function to wire up the autocomplete behaviour for this DOM element. We pass a URL to identify the source of the data. For this post I’ve simply created an ASP.NET MVC action that returns JSON data (shown below). Note that in the view I used Url.Action to look up the URL for this action in the routing table – avoid the temptation to hard-code the URL as this duplicates the routing table and makes it hard to change your routing later.
public ActionResult Autocomplete(string term)
{
var items = new[] {“Apple”, “Pear”, “Banana”, “Pineapple”, “Peach”};
var filteredItems = items.Where(
item => item.IndexOf(term, StringComparison.InvariantCultureIgnoreCase) >= 0
);
return Json(filteredItems, JsonRequestBehavior.AllowGet);
}
https://blogs.msdn.microsoft.com/stuartleeks/2012/04/23/asp-net-mvc-jquery-ui-autocomplete/
I have a Partial View that can currently display three cards/boxes that contain snippets of information about different case studies. I want this page to on load, display all the cards, but then also have a dropdown menu that filters each card by their CaseStudyIndustry property and be able to go back to displaying all the cards when you select "Select an industry"/the default selection.
I got a lot of help from http://weblogs.thinktecture.com/cnagel/2011/06/filter-and-display-data-with-aspnet-mvc-part-2partial-views-and-jquery.html, but I can't seem to get all the cards to display onload or when selecting the default DropDownList item. I've been stuck on this for a few weeks.
Here is my code:
Partial View:
#model IEnumerable<KenCast.Models.CaseStudies>
#foreach (var item in Model)
{
await Html.RenderPartialAsync("_CaseStudyCard.cshtml", item);
}
Index/page with the dropdown menu:
<h1>#ViewData["Title"]</h1>
<fieldset>
<div>
#Html.DropDownList("Industries", "Select an industry")
</div>
<br />
<div id="target">
</div>
<div id="log">
</div>
</fieldset>
<h3>For development only</h3>
<p>This link below to create new application is for development only. Will change once Identity is added to this app.</p>
<p>
<a asp-action="Create">Create New</a>
</p>
Script from: http://weblogs.thinktecture.com/cnagel/2011/06/filter-and-display-data-with-aspnet-mvc-part-2partial-views-and-jquery.html
$(document).ready(function () {
$("#Industries").change(function () {
$("#log").ajaxError(function (event, jqxhr, settings, exception) {
alert(exception);
});
// loads all cards from all industries
// Changes cards by industry when selected from dropdown menu
var industrySelected = $("select option:selected").text();
$.get('#Url.Action("CaseStudiesByIndustryPartial")', { id: industrySelected }, function (data) {
$("#target").html(data);
});
});
});
Controller:
public IActionResult Index()
{
var industries = new SelectList(_context.CaseStudies.Select(c => c.CaseStudyIndustry).Distinct().ToList());
ViewBag.Industries = industries;
return View();
}
public PartialViewResult CaseStudiesByIndustryPartial(string id)
{
return PartialView(
_context.CaseStudies.Where(c => c.CaseStudyIndustry == id).OrderBy(c => c.CaseStudyDate)
.ThenBy(c => c.CaseStudyTitle).ToList());
}
Any help would be greatly appreciated. Thank you!!
Figured this out with the hints from Stephen Muecke. The value of the first item selected in the dropbox was "Select an industry", so I used an if statement to change the displayed cards when "Select an industry was selected.
Code within the Controller now looks like this:
//Responsible for filtering case studies when item in DropDownList is selected.
public PartialViewResult CaseStudiesByIndustryPartial(string id)
{
if (id == "Select an industry") return PartialView(
_context.CaseStudies.OrderByDescending(c => c.CaseStudyDate)
.ThenBy(c => c.CaseStudyTitle).ToList());
else return PartialView(
_context.CaseStudies.Where(c => c.CaseStudyIndustry == id).OrderByDescending(c => c.CaseStudyDate)
.ThenBy(c => c.CaseStudyTitle).ToList());
}
Not sure if this is the most elegant way to do this, but it works! If anyone has another suggestion for how to write this without repeating code, please let me know!
The code in the controller, changed the cards in the view, but would only display all of the cards after I had selected another industry and then selected "Select an industry".
I ended up creating a ViewComponent that loaded all of the cards when the page loaded. The ViewComponent ended up looking like this:
namespace KenCast.ViewComponents
{
public class CaseStudiesViewComponent : ViewComponent
{
//allows for data access
private readonly ApplicationDbContext _context;
public CaseStudiesViewComponent(ApplicationDbContext c)
{
_context = c;
}
public Task<IViewComponentResult> InvokeAsync()
{
var casestudies = (from cs in _context.CaseStudies.ToList()
.OrderByDescending(cs => cs.CaseStudyDate)
.ThenBy(cs => cs.CaseStudyTitle)
select cs).ToList();
return Task.FromResult<IViewComponentResult>(View(casestudies));
}
}
}
I called the ViewComponent in the index page (page with the dropdown menu). The index page now looks like this:
<h1>#ViewData["Title"]</h1>
<fieldset>
<div>
#Html.DropDownList("Industries", "Select an industry")
</div>
<br />
<div id="target"> #* Loads data from CaseStudiesViewComponent *#
#await Component.InvokeAsync("CaseStudies")
</div>
<div id="log">
</div>
</fieldset>
<h3>For development only</h3>
<p>This link below to create new application is for development only. Will change once Identity is added to this app.</p>
<p>
<a asp-action="Create">Create New</a>
</p>
#* Script from: http://weblogs.thinktecture.com/cnagel/2011/06/filter-and-display-data-with-aspnet-mvc-part-2partial-views-and-jquery.html *#
<script type="text/javascript">
$(document).ready(function () {
$("#Industries").change(function () {
$("#log").ajaxError(function (event, jqxhr, settings, exception) {
alert(exception);
});
//loads all cards from all industries
//Changes cards by industry when selected from dropdown menu
var industrySelected = $("select option:selected").text();
$.get('#Url.Action("CaseStudiesByIndustryPartial")',
{ id: industrySelected }, function (data) {
$("#target").html(data);
});
});
});
</script>
Hope this helps if anyone else runs into a similar issue.
My problem: drop down list at layout page.
I've read this post: ASP.NET MVC Razor pass model to layout it's more or less similar to my problem.
In one of comments Mattias Jakobsson wrote that: "But a common solution is to use RenderAction to render parts that need their own data in the layout page".
So ok I've created layout page with #Html.Action() that render my drop dwon list with a date from the db. Everything's perfect. But...
I have two pages, for example: 'Home', 'About' and my drop down list (ddl) at layout page
How to achive that when I'm at 'Home' and I changed selection in ddl it refresh 'Home' page and when I'm at 'About' it refresh 'About' page.
How to store selected ddl value through pages?
Part of Layout.cshtml code:
.
.
<body>
<header id="top" class="grid-full-margin">
<strong id="logo" class="grid-304"><img src="/images/logo.png" ></strong>
#Html.ActionLink(#Resources.Resource.BackToIntranet, "Index", "Home", null, new {#class = "link link-home grid-position-left"})
<h1>#Resources.Resource.SiteTitle</h1>
#Resources.Resource.LayoutHelp
<nav clss="grid-896">
<ul>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem1, "Index", "Home")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem2, "Index", "ClimaticStation")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem3, "Index", "ClimaticPoint")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem4, "Index", "IcewaterExchanger")</li>
<li>#Html.ActionLink(Resources.Resource.LayoutMenuItem5, "Index", "Pipeline")
<ul>
<li>#Html.ActionLink("Zestawienie", "YearsLength", "Pipeline")</li>
</ul>
</li>
</ul>
<div class="mod-select-list tbl-actions">
#Html.Partial("~/Views/Shared/Partials/LoginPartial.cshtml")
</div>
</nav>
</header>
<form action="#">
#Html.Action("VariantsDdl", "MyBase")
</form>
#RenderBody()
.
.
Part of MyBaseController.cs
public class MyBaseController : Controller
{
[ChildActionOnly]
public ActionResult VariantsDdl()
{
var dataFromDb = GetDataFromDB(); // it's not importstn right now
return this.PartialView("~/Views/Shared/Partials/VariantsDdlPartial.cshtml", dataFromDb);
}
.
.
}
Regards,
Marcin
ok I've managed to solve this problem and I want to know your opinion abut my solution.
_Layout.cshtml looks the same way like at first post, so belowe is only most important part for this question (drop down list at layout)
<div style="float: right;">
#Html.Action("VariantsDdl", "MyBase")
</div>
Action: VariantsDdl is implemented at MyBaseController. This action loads selected variant id from session or if it's null then from web.config (in this situation it's project requirement that at least one variant must be present at db and its id must be specified in config):
[ChildActionOnly]
public ActionResult VariantsDdl()
{
long defaultVariantID;
long.TryParse(System.Configuration.ConfigurationManager.AppSettings["DefaultVariantId"], out defaultVariantID);
if (System.Web.HttpContext.Current.Session["mySelectedVariant"] != null)
{
long.TryParse(System.Web.HttpContext.Current.Session["mySelectedVariant"].ToString(), out defaultVariantID);
}
var variants = this.db.warianties.ToList();
var items = new List<SelectListItem>();
foreach (var variant in variants)
{
var selectedItem = false;
if(variant.id == defaultVariantID)
{
selectedItem = true;
}
items.Add(new SelectListItem { Selected = selectedItem, Text = variant.nazwa, Value = variant.id.ToString() });
}
return this.PartialView("~/Views/Shared/Partials/VariantsDdlPartial.cshtml", items);
}
Partial view and post action that stores selected variant id to session:
#model IEnumerable<SelectListItem>
<label for="field">Current variant</label>
#Html.DropDownList("Varaints", Model, new { id = "variantsDdl" })
<script type="text/javascript">
$(function () {
$('#variantsDdl').change(function () {
var val = $('#variantsDdl').val()
$.ajax({
type: "POST",
url: '#Url.Action("ChangeVariant", "MyBase")' + '/' + val,
success: function (result) {
location.reload();
},
error: function (data) { alert('Error'); }
});
});
});
Partial View post action 'ChangeVariant', saves selected variant id to session:
[HttpPost]
public ActionResult ChangeVariant(long id = 0)
{
System.Web.HttpContext.Current.Session["mySelectedVariant"] = id;
return null;
}
This is solution for my requirements:
1. DDL at layout
2. Refresh current page at DDL 'onchange'
3. Keep selected DDL value through pages
Please comment if it's appropriate solution or maybe should I go different way?
Regards,
Marcin