Image Slider does not work at random moments - c#

I have created an Image Slider using jQuery, but it doesn't work at random moments. After reloading the page I get the following error:
Uncaught TypeError: Cannot read property 'indexOf' of undefined
at i.fn.init.i.fn.load (jquery?v=eJAcMfrInnLuvmR6YmGFt2ky0cO2ssn2OaxtB6iWFKQ1:1)
at HTMLImageElement.<anonymous> (slider?v=iXGFgGvKoKTyJMnF1faQOZMvYM6od0eK7irNUQ3FiMg1:1)
at Function.each (jquery?v=eJAcMfrInnLuvmR6YmGFt2ky0cO2ssn2OaxtB6iWFKQ1:1)
at i.fn.init.each (jquery?v=eJAcMfrInnLuvmR6YmGFt2ky0cO2ssn2OaxtB6iWFKQ1:1)
at HTMLImageElement.<anonymous> (slider?v=iXGFgGvKoKTyJMnF1faQOZMvYM6od0eK7irNUQ3FiMg1:1)
at Function.each (jquery?v=eJAcMfrInnLuvmR6YmGFt2ky0cO2ssn2OaxtB6iWFKQ1:1)
at i.fn.init.each (jquery?v=eJAcMfrInnLuvmR6YmGFt2ky0cO2ssn2OaxtB6iWFKQ1:1)
at et (slider?v=iXGFgGvKoKTyJMnF1faQOZMvYM6od0eK7irNUQ3FiMg1:1)
at ft (slider?v=iXGFgGvKoKTyJMnF1faQOZMvYM6od0eK7irNUQ3FiMg1:1)
at k (slider?v=iXGFgGvKoKTyJMnF1faQOZMvYM6od0eK7irNUQ3FiMg1:1)
Controller:
public class SliderController : Controller
{
// GET: Slider
public ActionResult Index()
{
using (BasDbContext db = new BasDbContext())
{
return View(db.gallery.ToList());
}
//return View();
}
//Add Images in slider
public ActionResult AddImage()
{
return View();
}
[HttpPost]
public ActionResult AddImage(HttpPostedFileBase ImagePath)
{
if (ImagePath != null)
{
// You can skip this block, because it is only to force the user to upload specific resolution pics
//System.Drawing.Image img = System.Drawing.Image.FromStream(ImagePath.InputStream);
//if ((img.Width != 800) || (img.Height != 356))
//{
// ModelState.AddModelError("", "Image resolution must be 800 x 356 pixels");
// return View();
//}
// Upload your pic
string pic = System.IO.Path.GetFileName(ImagePath.FileName);
string path = System.IO.Path.Combine(Server.MapPath(#"\cdm\Content\images\"), pic);
ImagePath.SaveAs(path);
using (BasDbContext db = new BasDbContext())
{
Gallery gallery = new Gallery { ImagePath = #"\cdm\Content\images\" + pic };
db.gallery.Add(gallery);
db.gallery.Add(gallery).DateAdded = gallery.DateAdded = DateTime.Now;
db.SaveChanges();
}
}
return RedirectToAction("Index");
}
// Delete Multiple Images
public ActionResult DeleteImages()
{
using (BasDbContext db = new BasDbContext())
{
return View(db.gallery.ToList());
}
}
[HttpPost]
public ActionResult DeleteImages(IEnumerable<int> ImagesIDs)
{
using (BasDbContext db = new BasDbContext())
{
try
{
foreach (var id in ImagesIDs)
{
var image = db.gallery.Single(s => s.ID == id);
string imgPath = Server.MapPath(image.ImagePath);
db.gallery.Remove(image);
if (System.IO.File.Exists(imgPath))
System.IO.File.Delete(imgPath);
}
db.SaveChanges();
}
catch
{
TempData["AlertMessage"] = "Something went wrong, try again";
}
}
return RedirectToAction("DeleteImages");
}
}
}
Index:
#model IEnumerable<ConcremoteDeviceManagment.Models.Gallery>
#{
ViewBag.Title = "Index";
//Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (TempData["AlertMessage"] != null)
{
<p class="alert alert-danger" id="successMessage">#TempData["AlertMessage"]</p>
}
<h2>Index</h2>
<p>
<button onclick="location.href='#Url.Action("AddImage", "Slider")';return false; " class="btn btn-primary">Add Image</button>
<button onclick="location.href='#Url.Action("DeleteImages", "Slider")';return false; " class="btn btn-danger">Delete Image</button>
</p>
#Html.Partial("~/Views/Shared/SliderPartial.cshtml", Model)
SliderPartial:
<div class="bxslider">
#foreach (var image in Model)
{
<div><img src="#Url.Content(image.ImagePath)" /></div>
}
</div>
<script>
$(document).ready(function () {
$('.bxslider').bxSlider({
mode: 'fade',
captions: true,
slideWidth: 600
});
});
</script>
I think something is going wrong in SliderPartial.
Controller and Index seems to be fine.
I hope somebody is able to help me out.
More information will be given when needed

Related

ViewBag.Message not showing ASP.NET MVC c#

I have a view named Index.cshtml and controller named HomeController and I can't seem to show the ViewBag.Message and ViewBag.FileUrl to the view. The code is working I just can't show the ViewBag.message when the file is successfully uploaded.
Here's my code below
Index.cshtml
#{
ViewBag.Title = "Upload a file to S3 Bucket";
}
<h2>#ViewBag.Title.</h2>
<h3>#ViewBag.Message</h3>
<h3>#ViewBag.FileUrl</h3>
<p>Use this area to browse image and upload to S3 bucket.</p>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div>
#Html.TextBox("file", "", new { type = "file" }) <br />
<input type="submit" value="Upload" />
#ViewBag.FileUrl
#ViewBag.Message
</div>
}
HomeController.cs
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
var s3Client = new AmazonS3Client(accesskey, secretkey, bucketRegion);
var result = "";
var keyName = file.FileName;
var fileTransferUtility = new TransferUtility(s3Client);
try
{
if (file.ContentLength > 0)
{
var filePath = Path.Combine(Server.MapPath("~/App_Data"), Path.GetFileName(file.FileName));
var fileTransferUtilityRequest = new TransferUtilityUploadRequest
{
BucketName = bucketName,
FilePath = filePath,
StorageClass = S3StorageClass.StandardInfrequentAccess,
PartSize = 6291456, // 6 MB.
Key = keyName,
CannedACL = S3CannedACL.PublicRead
};
fileTransferUtilityRequest.Metadata.Add("param1", "Value1");
fileTransferUtilityRequest.Metadata.Add("param2", "Value2");
fileTransferUtility.Upload(fileTransferUtilityRequest);
fileTransferUtility.Dispose();
}
result = string.Format("http://{0}.s3.amazonaws.com/{1}", bucketName, keyName);
ViewBag.FileUrl = result;
ViewBag.Message = "File Uploaded Successfully!!";
}
catch (AmazonS3Exception amazonS3Exception)
{
ViewBag.Message = "Error occurred: " + amazonS3Exception.Message;
}
return RedirectToAction("Index");
}
You assign ViewBag values, which are lost by the subsequent RedirectToAction().
Found the answer here, with detailed comparison of ViewData, ViewBag, and TempData. In your case, TempData should work.
You are doing redirect the result so that value becomes null, instead of that use Tempdata in where assign a value and get it where you redirect,
catch (AmazonS3Exception amazonS3Exception)
{
Tempdata["Message"]="Error occurred: " + amazonS3Exception.Message;
}
and Index action method, try it like below ,
[HttpGet]
public ActionResult Index()
{
ViewBag.Message= (string)Tempdata["Message"]
return View();
}

MVC4 Custom Login Controller

I need some help with some MVC stuff. I'm trying to update some legacy code I inherited, and am an absolute n00b with web stuff. This same exact code works on the installed version of the site, but will not work correctly here.
The Index.chtml file is:
#model QspAudits.Models.LoginModel
#{
Layout = null;
// Unimportant viewbag stuff. Can post if needed.
}
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Site | #ViewBag.Title</title>
#Styles.Render("http://hotline.rimg.net/qspaudits/Content/css/qsp.css")
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
function submitenter(myfield, e) {
var keycode;
if (window.event) keycode = window.event.keyCode;
else if (e) keycode = e.which;
else return true;
if (keycode == 13) {
$("#FormLogin").submit();
return false;
}
else
return true;
}
$(document).ready(function () {
$('.login_btn').click(function () {
$(this).closest('form').submit();
});
});
</script>
</head>
<body id="#ViewBag.BodyID" class="#ViewBag.BodyClass">
#using (Html.BeginForm("Index", "Login", FormMethod.Post, new {id = "FormLogin"}))
{
<div id="loginBox" class="login">
<div class="loginForm">
<img alt="" src="#Url.Content("~/Images/samsclub_medlogo.png")" class="identity"/>
<h2>#ViewBag.Site</h2>
<label>Login</label>
#Html.TextBoxFor(x => x.username, new { #class = "TextBox", #autofocus=""})
<label>Password</label>
#Html.PasswordFor(x => x.password, new { #class = "PasswordBox", #onkeypress = "return submitenter(this,event)" })
<div id="login_btn" class="login_btn"></div> <span>#Model.message</span>
</div>
</div>
}
</body>
</html>
The LoginController.cs looks like:
namespace QspAudits.Controllers
{
public class LoginController : Controller
{
private QspAuditsEntities db = new QspAuditsEntities();
private BT8_GCEntities bt_db = new BT8_GCEntities();
[HttpGet]
[AllowAnonymous]
public ActionResult Index()
{
ViewBag.bodyID = "login";
LoginModel log = new LoginModel();
log.message = "";
return View(log);
}
[HttpPost]
[AllowAnonymous]
public ActionResult Index(LoginModel formResult)
{
UserLogin_Result log = db.UserLogin(formResult.username).FirstOrDefault();
if (log != null && formResult.password != null)
{
int pass;
if (Int32.TryParse(log.password.ToString(), out pass) == true || log.validation == 1)
{
int dbPass = (log.validation == 3 ? pass : Common.MD5Hash(formResult.password));
if (dbPass == (int)log.password) //use real valid code
{
FormsAuthentication.SetAuthCookie(log.user_id.ToString() + "|" + log.full_name + "|" + (log.validation == 1 ? "1" : "3"), false);
return RedirectToAction("Index", "Home");
}
}
}
formResult.password = "";
formResult.message = "Incorrect Username/Password";
return View(formResult);
}
public ActionResult SignOut()
{
FormsAuthentication.SignOut();
return RedirectToAction("Index", "Login");
}
}
}
When I run the code to test (through VS2012), the only breakpoint that ever gets hit is in the [HttpGet] block. The strangeness is that it hits the [HttpGet] block breakpoint twice. The [HttpPost] block never gets touched.
This code is running on the live server, so it's got to be something stupid simple I'm missing.

better way to load 2 dropdown in mvc

This is how i am loading on page load state and city dropdown:
My Controller method:
This is the first method which is calling when page is loaded.
public ActionResult Index()
{
var states = GetStates();
var cities = Enumerable.Empty<SelectListItem>();
ViewBag.States = states;
ViewBag.Cities = cities;
}
private IEnumerable<SelectListItem> GetStates()
{
using (var db = new DataEntities())
{
return db.States.Select(d => new SelectListItem { Text = d.StateName, Value =d.Id.ToString() });
}
}
[HttpGet]
public ActionResult GetCities(int id)
{
using (var db = new DataEntities())
{
var data = db.Cities.Where(d=>d.StateId==id).Select(d => new { Text = d.CityName, Value = d.Id }).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
}
My View:
IEnumerable<SelectListItem> States = ViewBag.States;
IEnumerable<SelectListItem> Cities = ViewBag.Cities;
#Html.DropDownList("State", States, "Select State", new { onchange="loadCities(this)"})
#Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity"})
function loadCities(obj) {
$.ajax({
url: "/Home/GetCities",
data: { id: $(obj).val() },
contentType:"application/json",
success:function(responce){
var html = '<option value="0">Select City</option>';
$(responce).each(function () {
html += '<option value="'+this.Value+'">'+this.Text+'</option>'
});
$("#ddlCity").html(html);
}
});
}
Any better way then this to load state and city dropdown?
public class HomeController : Controller
{
public ActionResult Index(int id=0)
{
Person model = null;
var states = GetStates().ToList();
var cities = Enumerable.Empty<SelectListItem>();
if (id > 0)
{
using (var db = new DataEntities())
{
model = db.People.Include("City").FirstOrDefault(d => d.Id == id);
if (model == null)
model = new Person();
else
{
states.First(d => d.Value == model.City.StateId.ToString()).Selected = true;
cities = db.Cities.Where(d => d.StateId == model.City.StateId).ToList().Select(d => new SelectListItem { Text = d.CityName,Value=d.Id.ToString(),Selected=d.Id==model.CityId });
}
}
}
else
{
model = new Person();
}
ViewBag.States = states;
ViewBag.Cities = cities;
ViewBag.Persons = GetPersons();
return View(model);
}
[HttpGet]
public ActionResult GetCities(int id)
{
using (var db = new DataEntities())
{
var data = db.Cities.Where(d=>d.StateId==id).Select(d => new { Text = d.CityName, Value = d.Id }).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
}
public ActionResult SavePersonDetail([Bind(Exclude = "Id")] Person model)
{
// var employeeDal= new Emploee();
//employee.firstname=model.
if (ModelState.IsValid)
{
var Id = model.Id;
int.TryParse(Request["Id"], out Id);
using (var db = new DataEntities())
{
if (Id > 0)
{
var person = db.People.FirstOrDefault(d => d.Id == Id);
if (person != null)
{
model.Id = Id;
db.People.ApplyCurrentValues(model);
}
}
else
{
db.People.AddObject(model);
}
db.SaveChanges();
}
}
if (!Request.IsAjaxRequest())
{
ViewBag.States = GetStates();
ViewBag.Persons = GetPersons();
ViewBag.Cities = Enumerable.Empty<SelectListItem>();
return View("Index");
}
else
{
return PartialView("_personDetail",GetPersons());
}
}
public ActionResult Delete(int id)
{
using (var db = new DataEntities())
{
var model = db.People.FirstOrDefault(d => d.Id == id);
if (model != null)
{
db.People.DeleteObject(model);
db.SaveChanges();
}
}
if (Request.IsAjaxRequest())
{
return Content(id.ToString());
}
else
{
ViewBag.States = GetStates();
ViewBag.Persons = GetPersons();
ViewBag.Cities = Enumerable.Empty<SelectListItem>();
return View("Index");
}
}
private IEnumerable<SelectListItem> GetStates()
{
using (var db = new DataEntities())
{
return db.States.ToList().Select(d => new SelectListItem { Text = d.StateName, Value =d.Id.ToString() });
}
}
private IEnumerable<Person> GetPersons()
{
using (var db = new DataEntities())
{
return db.People.Include("City").Include("City.State").ToList();
}
}
public ActionResult HomeAjax()
{
ViewBag.States = GetStates();
ViewBag.Cities = Enumerable.Empty<SelectListItem>();
using (var db = new DataEntities())
{
var data = db.States.Include("Cities").Select(d => new { Id = d.Id, Name = d.StateName, Cities = d.Cities.Select(x => new { Id=x.Id,Name=x.CityName}) }).ToList();
ViewBag.CityStateJson = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(data);
}
ViewBag.Persons = GetPersons();
return View();
}
}
#model IEnumerable<Person>
<div>
<table>
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th>
Email
</th>
<th>
City
</th>
<th>
State
</th>
<th>
Edit
</th>
</tr>
#if (Model.Count() == 0)
{
<tr>
<td colspan="6">
<h3>No data available</h3>
</td>
</tr>
}
else {
foreach (var item in Model) {
<tr data-id="#item.Id">
<td data-id="fn">#item.FirstName</td>
<td data-id="ln">#item.LastName</td>
<td data-id="email">#item.Email</td>
<td data-id="cn">#item.CityName<input type="hidden" value="#item.CityId" /></td>
<td>#item.StateName</td>
<td>
#if (ViewBag.Title == "Home Ajax" || Request.IsAjaxRequest())
{
Update
<span>#Ajax.ActionLink("Delete", "Delete", new { id = item.Id }, new AjaxOptions {OnSuccess="deleteSuccess",OnBegin="showLoader",OnComplete="hideLoader" })</span>
}
else {
<span>#Html.ActionLink("Update", "Index", new { id = item.Id })</span>
<span>#Html.ActionLink("Delete", "Delete", new { id = item.Id })</span>
}
</td>
</tr>
}
}
</table>
</div>
#model Person
#{
ViewBag.Title = "Home Ajax";
IEnumerable<Person> persons = ViewBag.Persons;
IEnumerable<SelectListItem> States = ViewBag.States;
IEnumerable<SelectListItem> Cities = ViewBag.Cities;
IEnumerable<State> fullStates=ViewBag.CityStates;
}
#section featured {
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
</div>
</section>
}
#section styles{
<style type="text/css">
td,th {
border:1px solid;
padding:5px 10px;
}
select {
padding:5px 2px;
width:310px;
font-size:16px;
}
</style>
}
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
var jsonArray = #Html.Raw(ViewBag.CityStateJson)
function clearValues() {
$("input[type='text'],select").val('');
$("input[type='hidden'][name='Id']").val(0);
}
function loadCities(obj) {
for (var i = 0; i < jsonArray.length; i++) {
if (jsonArray[i].Id == parseInt($(obj).val())) {
fillCity(jsonArray[i].Cities);
break;
}
}
}
function Edit(obj, Id) {
// alert("hi")
$("input[type='hidden'][name='Id']").val(Id);
var tr = $(obj).closest("tr");
$("#txtfirstName").val($("td[data-id='fn']", tr).text().trim());
$("#txtlastName").val($("td[data-id='ln']", tr).text().trim());
$("#txtemail").val($("td[data-id='email']", tr).text().trim());
var city = $("td[data-id='cn'] input[type='hidden']", tr).val();
var state;
for (var i = 0; i < jsonArray.length; i++) {
for (var j = 0; j < jsonArray[i].Cities.length; j++) {
if (jsonArray[i].Cities[j].Id == parseInt(city)) {
state = jsonArray[i].Id;
break;
}
}
if (state) {
fillCity(jsonArray[i].Cities);
break;
}
}
$("#ddlState").val(state);
$("#ddlCity").val(city);
}
function fillCity(obj) {
var html = '<option value="0">Select City</option>';
$(obj).each(function () {
html += '<option value="' + this.Id + '">' + this.Name + '</option>'
});
$("#ddlCity").html(html);
}
function deleteSuccess(responce) {
alert("record deleted successfully");
$("tr[data-id='" + responce + "']").remove();
}
function insertSuccess() {
alert("Record saved successfully");
clearValues();
}
function showLoader() {
$("#overlay").show();
}
function hideLoader() {
$("#overlay").hide();
}
</script>
}
<h3>Add Personal Detail</h3>
#using (Ajax.BeginForm("SavePersonDetail", "Home", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "personList" ,OnSuccess="insertSuccess",OnBegin="showLoader",OnComplete="hideLoader"}))
{
#Html.HiddenFor(m => m.Id);
<ol class="round">
<li>
#Html.LabelFor(m => m.FirstName)
#Html.TextBoxFor(m => m.FirstName, new { id = "txtfirstName" })
#Html.ValidationMessageFor(m => m.FirstName)
</li>
<li>
#Html.LabelFor(m => m.LastName)
#Html.TextBoxFor(m => m.LastName, new { id = "txtlastName" })
#Html.ValidationMessageFor(m => m.LastName)
</li>
<li>
#Html.LabelFor(m => m.Email)
#Html.TextBoxFor(m => m.Email, new { id = "txtemail" })
#Html.ValidationMessageFor(m => m.Email)
</li>
<li>
#Html.Label("State")
#Html.DropDownList("State", States, "Select State", new { onchange = "loadCities(this)", id = "ddlState" })
</li>
<li>
#Html.LabelFor(m => m.CityId)
#Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id = "ddlCity" })
#Html.ValidationMessageFor(m => m.CityId)
</li>
</ol>
<input type="submit" value="Save" />
<input type="button" value="Cancel" onclick="clearValues();"/>
}
<h2>
Person List
</h2>
<div style="position:fixed;text-align:center;top:0;bottom:0;left:0;right:0;z-index:10;background-color:black;opacity:0.6;display:none;" id="overlay">
<img style="position:relative;top:370px" src="~/Images/ajax-loader.gif" />
</div>
<div id="personList">
#Html.Partial("_personDetail", persons)
</div>
You approach using ajax is fine although I would recommend a few better practices including using a view model with properties for StateID, CityID StateList and CityList, and using Unobtrusive JavaScript rather than polluting you markup with behavior, and generating the first ("please select") option with a null value rather than 0 so it can be used with the [Required] attribute
HTML
#Html.DropDownList(m => m.StateID, States, "Select State") // remove the onchange
#Html.DropDownListFor(m => m.CityID, Cities, "Select City") // why change the default ID?
SCRIPT
var url = '#Url.Action("GetCities", "Home")'; // use the helper (dont hard code)
var cities = $('#CityID'); // cache the element
$('#StateID').change(function() {
$.getJSON(url, { id: $(this).val() }, function(response) {
// clear and add default (null) option
cities.empty().append($('<option></option>').val('').text('Please select'));
$.each(response, function(index, item) {
cities.append($('<option></option>').val(item.Value).text(item.Text));
});
});
});
If you were rendering multiple items (say you were asking the user to select their last 10 cities they visited), you can cache the result of the first call to avoid repeated calls where their selections may include cities from the same state.
var cache = {};
$('#StateID').change(function() {
var selectedState = $(this).val();
if (cache[selectedState]) {
// render the options from the cache
} else {
$.getJSON(url, { id: selectedState }, function(response) {
// add to cache
cache[selectedState] = response;
.....
});
}
});
Finally, in response to your comments regarding doing it without ajax, you can pass all the cities to the view and assign them to a javascript array. I would only recommend this if you have a few countries, each with a few cities. Its a matter of balancing the slight extra initial load time vs the slight delay in making the ajax call.
In the controller
model.CityList = db.Cities.Select(d => new { City = d.CountryID, Text = d.CityName, Value = d.Id }).ToList();
In the view (script)
// assign all cities to javascript array
var allCities= JSON.parse('#Html.Raw(Json.Encode(Model.CityList))');
$('#StateID').change(function() {
var selectedState = $(this).val();
var cities = $.grep(allCities, function(item, index) {
return item.CountryID == selectedState;
});
// build options based on value of cities
});
This is a correct approach, but you can simplify your javascript:
function loadCities(obj) {
$.getJSON("/Home/GetCities", function (data) {
var html = '<option value="0">Select City</option>';
$(data).each(function () {
html += '<option value="'+this.Value+'">'+this.Text+'</option>'
});
$("#ddlCity").html(html);
});
}
Further possible simplification:
Add the default item (Select City) server-side, so your javascript will be smaller.
Here's how I'd do it without the page refresh, assuming the list of cities isn't too long.
I'm assuming you can create a GetStatesAndCities method to return a Dictionary.
public ActionResult Index()
{
Dictionary<string, List<String>> statesAndCities = GetStatesAndCities();
ViewBag.StatesAndCities = Json(statesAndCities);
}
Then in the view:
var states = JSON.parse(#ViewBag.StatesAndCities);
function loadCities(obj) {
var cities = states[$(obj).val()];
var html = '<option value="0">Select City</option>';
$(cities).each(function () {
html += '<option value="'+this.Value+'">'+this.Text+'</option>'
});
$("#ddlCity").html(html);
}
This way when the state is changed the cities field with update immediately with no need for callback.
disclaimer: This is not a code answer, there are plenty other answers.
I think best way to keep yourself happy to seperate UI pages from data => turn them into API calls:
/GetCities
/GetStates
Now you can simply leave the select's empty on Razor rendering the page. And use a Jquery/Bootstrap plugin to create an AJAX select box.
This way when the user stops typing his search, this search string can than be send with the AJAX call (eg: /GetStates?search=test) and then a small result set can be send back to the website.
This gives:
Better separation in serveside code
Better User eXperience.
Smaller page loads (since you no longer send all the options to user when he requests the page, only when he opens the select box).
How about using Knockout?
Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model
You have to use ajax for your cities. But with knockout you dont need to write
var html = '<option value="0">Select City</option>';
$(responce).each(function () {
html += '<option value="'+this.Value+'">'+this.Text+'</option>'});
$("#ddlCity").html(html);
in your javascript.Knockout makes it simple.
You can simply write:
function CityModel() {
var self = this; // that means this CityModel
self.cities = ko.observableArray([]);
self.getCities = function () {
$.ajax({
url: "/Home/GetCities",
data: { id: $(obj).val() },
contentType: "application/json",
success: self.cities
});
}
}
ko.applyBindings(new CityModel());
thats all. But you have to bind your data into html elements.
Instead of using :
#Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity"})
You can use:
<select data-bind="options:cities,optionsValue:"Id",optionsText:"CityName",optionsCaption:"Select City""></select>
or you can mix razor and knockout:
#Html.DropDownListFor(m => m.CityId, Cities, "Select City", new { id="ddlCity",data_bind:"options:cities,optionsValue:\"Id\",optionsText:\"CityName\""})
One more thing you have to call GetCities when State changes, you can :
#Html.DropDownList("State", States, "Select State", new {data_bind:"event:\"change\":\"$root.GetCities\""})
Dont be scare with \"\" things this because " is an escape character and we have to say to razor i want to use " by using \ before it.
You can find more info about knockout :Knockout
And mixing with razor: Razor and Knockout
Ps: yes using knockout is suspend us from Razor and Mvc. You have to write another ViewModel . But like this situations ko is helpful. Mixing razor and knockout is another option for you.

How to display a Json message in a div inside a Html.BeginForm View

Here is the code for my view and controller
#using (Html.BeginForm("PdfHeaderAndFooterManager", "Dashboard", FormMethod.Post, new { enctype = "multipart/form-data", id = "formPdfImages" }))
div id="resultMessage"></div>
}
CONTROLLER ACTION
public ActionResult PdfHeaderAndFooterManager(HttpPostedFileBase headerImage, HttpPostedFileBase footerImage)
{
//some code to declare variables
if (headerImage != null)
{
if (!String.IsNullOrEmpty(headerImage.ContentType))
{
headerImageContentType = imageHelper.IsValidImageType(headerImage.ContentType);
if (headerImageContentType)
{
resizedHeaderImage = imageHelper.ResizeImage(headerImage.InputStream);
}
else
{
return Json(new { success = false, message = "Please Upload an image* file less than 2GB." });
}
}
}
if (footerImage != null)
{
if (!String.IsNullOrEmpty(footerImage.ContentType))
{
footerImageContentType = imageHelper.IsValidImageType(footerImage.ContentType);
if (footerImageContentType)
{
resizedFooterImage = imageHelper.ResizeImage(footerImage.InputStream);
}
else
{
return Json(new { success = false, message = "Please Upload an image* file less than 2GB." });
}
}
}
if (P24DataPrincipal.CurrentIdentity != null)
{
if (resizedHeaderImage != null || resizedFooterImage != null)
{
//add to DB code
return Json(new { success = true, message = "Image(s) Uploaded Successfully." });
}
else
{
return Json(new {success = false, message = "Upload atleast 1 image file." });
}
}
return View("someview");
}
Can someone please assist me on how would have to write a jquery function to just display the Json results returned in the action above in my view. THANKS
EDITORIAL NOTE
It would appear that you want to send back JSON OR an Image. You can probably do some interesting things with the HTML 5 Blob API (or sending the image back as a JSON payload with a DATA URI). In general, there is no simple solution to this, especially via AJAX.
END NOTE
Assuming jQuery 1.5 or better:
jQuery.post('/TheController/PdfHeaderAndFooterManager')
.success(function(d){
jQuery('#resultMessage').html(d.message).attr('data-action-success',d.success);
}).error(function(){
jQuery('#resultMessage').html('There was an error sending data to the server.').attr('data-action-success', false);
});
And then you can do something fun in CSS like.:
[data-action-success=true]{
color: green;
}
[data-action-success=false]{
color: red;
}
It strikes me that you're returning different types of results. This is fairly uncommon and I would recommend that you split the "Show the form action (a GET action)" and the "Save a form (a POST action)". The GET could return an HTML action result. The POST could always return JSON.
public ActionResult PdfHeaderAndFooterManager(HttpPostedFileBase headerImage, HttpPostedFileBase footerImage)
{
//some code to declare variables
if (headerImage != null)
{
if (!String.IsNullOrEmpty(headerImage.ContentType))
{
headerImageContentType = imageHelper.IsValidImageType(headerImage.ContentType);
if (headerImageContentType)
{
resizedHeaderImage = imageHelper.ResizeImage(headerImage.InputStream);
}
else
{
ViewBag.ResultMessage="<span style='color:red'">Please Upload an image* file less than 2GB.</span>";
return View();
}
}
}
if (footerImage != null)
{
if (!String.IsNullOrEmpty(footerImage.ContentType))
{
footerImageContentType = imageHelper.IsValidImageType(footerImage.ContentType);
if (footerImageContentType)
{
resizedFooterImage = imageHelper.ResizeImage(footerImage.InputStream);
}
else
{
ViewBag.ResultMessage="<span style='color:red'">Please Upload an image* file less than 2GB.</span>";
return View();
}
}
}
if (P24DataPrincipal.CurrentIdentity != null)
{
if (resizedHeaderImage != null || resizedFooterImage != null)
{
//add to DB code
ViewBag.ResultMessage="<span style='color:green'">Image(s) Uploaded Successfully.</span>";
return View();
}
else
{
ViewBag.ResultMessage="<span style='color:red'">Upload atleast 1 image file.</span>";
return View();
}
}
}
And in View,
#using (Html.BeginForm("PdfHeaderAndFooterManager", "Dashboard", FormMethod.Post, new { enctype = "multipart/form-data", id = "formPdfImages" })){
<div id="resultMessage">
#ViewBag.ResultMessage
</div>
}
Try this, hope it will help you.

ASP.NET MVC3 Sending Multiple forms from the same page

There are similar posts out there but they do not seem to represent my situation. Apologies in advance if this is a re-post.
I have my view as
#FileUpload.GetHtml(initialNumberOfFiles:1,allowMoreFilesToBeAdded:true,includeFormTag:true, uploadText: "Upload" )
#model IEnumerable<EpubsLibrary.Models.Partner>
#{ using (Html.BeginForm("Index","Epub"))
{
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
<input type="submit" value="send" id="pickPartner" hidden="hidden"/>
}
}
<script type="text/javascript">
$(".file-upload-buttons input").click(function () {
$("#pickPartner").click();
});
</script>
my controller is
[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload, FormCollection collection)
{
int selectedPartner, count =0;
//int selectedPartner = int.Parse(collection["PartnerID"]);
if(!int.TryParse(collection["PartnerID"], out selectedPartner))
{
selectedPartner = 0;
ModelState.AddModelError("", "You must pick a publishing agency");
}
IList<Partner> p = r.ListPartners();
ViewBag.Partners = new SelectList(p.AsEnumerable(), "PartnerID", "Name", selectedPartner);
//make sure files were selected for upload
if (fileUpload != null)
{
for (int i = 0; i < fileUpload.Count(); i++)
{
//make sure every file selected != null
if (fileUpload.ElementAt(i) != null)
{
count++;
var file = fileUpload.ElementAt(i);
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
// need to modify this for saving the files to the server
var path = Path.Combine(Server.MapPath("/App_Data/uploads"), Guid.NewGuid() + "-" + fileName);
file.SaveAs(path);
}
}
}
}
if (count == 0)
{
ModelState.AddModelError("", "You must upload at least one file!");
}
return View();
}
I am using the file upload helper from Microsoft Web Helpers to upload files. The problem I am having is the helper created a form and I have another form I need to submit data from as well on the same page.
I thought I could link the submit buttons so that when you click upload it also sent the other form data but the data is not being sent. Each form works independently of the other with no issue but I need them to work together. Any advice would be appreciated.
Ok I updated the view with
#model IEnumerable<EpubsLibrary.Models.Partner>
#{ using (Html.BeginForm("Index","Epub"))
{
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
#FileUpload.GetHtml(initialNumberOfFiles: 1, allowMoreFilesToBeAdded: true, includeFormTag: false, uploadText: "Upload")
<input type="submit" value="send" id="pickPartner"/>
}
}
But now the file data does not seem to be getting passed anymore.
-- Update --
I have made the following changes.
The view now looks like
#model IEnumerable<EpubsLibrary.Models.Partner>
#{ using (Html.BeginForm("Index", "Epub", new { enctype = "multipart/form-data" }))
{
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
#FileUpload.GetHtml(initialNumberOfFiles: 1, allowMoreFilesToBeAdded: true, includeFormTag: false, uploadText: "Upload")
<input type="submit" value="send" id="pickPartner"/>
}
}
and the controller
[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload, int PartnerID = 0)
//public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload, FormCollection collection)
{
int count =0;
IList<Partner> p = r.ListPartners();
ViewBag.Partners = new SelectList(p.AsEnumerable(), "PartnerID", "Name", PartnerID);
//make sure files were selected for upload
if (fileUpload != null)
{
for (int i = 0; i < fileUpload.Count(); i++)
{
//make sure every file selected != null
if (fileUpload.ElementAt(i) != null)
{
count++;
var file = fileUpload.ElementAt(i);
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
// need to modify this for saving the files to the server
var path = Path.Combine(Server.MapPath("/App_Data/uploads"), Guid.NewGuid() + "-" + fileName);
file.SaveAs(path);
}
}
}
}
if (count == 0)
{
ModelState.AddModelError("", "You must upload at least one file!");
}
return View();
}
}
I am trying to figure out how the file data is getting sent over in the post (if it is) so I can save the files.
-- Final Update with Answer --
Well the problem turned out to be two fold.. 1st the issue with #FileUpload and needing to set includeFormTag: false
The other problem I discovered was I needed to make sure in my #Html.BeginForm I included FormMethod.Post This was discovered when the fileUpload count kept coming back as 0. I ran the profiler on firebug and it pointed out that the file data was not actually getting posted. Here is the corrected code below.
my view
#model IEnumerable<EpubsLibrary.Models.Partner>
#{ using (Html.BeginForm("Index", "Epub", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
#FileUpload.GetHtml(initialNumberOfFiles: 1, allowMoreFilesToBeAdded: true, includeFormTag: false, uploadText: "Upload")
<input type="submit" value="send" id="pickPartner"/>
}
}
my controller
[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload, int PartnerID = 0)
{
int count =0;
IList<Partner> p = r.ListPartners();
ViewBag.Partners = new SelectList(p.AsEnumerable(), "PartnerID", "Name", PartnerID);
//make sure files were selected for upload
if (fileUpload != null)
{
for (int i = 0; i < fileUpload.Count(); i++)
{
//make sure every file selected != null
if (fileUpload.ElementAt(i) != null)
{
count++;
var file = fileUpload.ElementAt(i);
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
// need to modify this for saving the files to the server
var path = Path.Combine(Server.MapPath("/App_Data/uploads"), Guid.NewGuid() + "-" + fileName);
file.SaveAs(path);
}
}
}
}
if (count == 0)
{
ModelState.AddModelError("", "You must upload at least one file!");
}
return View();
}
Thank you #Jay and #Vasile Bujac for your help with this.
Set IncludeFormTag to false and put it inside your other form using.
#model IEnumerable<EpubsLibrary.Models.Partner>
#{ using (Html.BeginForm("Index","Epub"))
{
#FileUpload.GetHtml(initialNumberOfFiles:1,allowMoreFilesToBeAdded:true,includeFormTag:false, uploadText: "Upload" )
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
<input type="submit" value="send" id="pickPartner" hidden="hidden"/>
}
}
Update:
Try changing the signature of your view to this:
public ActionResult Index(IEnumerable<HttpPostedFileBase> fileUpload, int PartnerID = 0)
Check the overloads for FileUpload.GetHtml and see if there is a parameter to set the field name for your file uploads. Previously it was just the files being uploaded, now its files and a parameter, so naming becomes more important.
You should use the same form for dropdownlist and file inputs. You can do this by putting the FileUpload helper inside the form, and setting "includeFormTag" parameter to false.
#model IEnumerable<EpubsLibrary.Models.Partner>
#using (Html.BeginForm("Index","Epub")) {
#FileUpload.GetHtml(initialNumberOfFiles:1,allowMoreFilesToBeAdded:true,includeFormTag:false, uploadText: "Upload" )
#Html.DropDownList("PartnerID", (IEnumerable<SelectListItem>)ViewBag.Partners, "None")
<input type="submit" value="send" id="pickPartner" hidden="hidden"/>
}

Categories

Resources