Returning string to _Layout.cshtml using PartialView - asp.net-mvc

I'm trying to return a string list to a navigation menu that appears on the side of my _Layout.cshtml page. I can return a string fine, but I'm supposed to be returning a PartialViewResult. This is the error I get:
{"The partial view 'Menu' was not found or no view engine supports the searched locations. The following locations were searched:\r\n~/Views/Nav/Menu.aspx\r\n~/Views/Nav/Menu.ascx\r\n~/Views/Shared/Menu.aspx\r\n~/Views/Shared/Menu.ascx\r\n~/Views/Nav/Menu.cshtml\r\n~/Views/Nav/Menu.vbhtml\r\n~/Views/Shared/Menu.cshtml\r\n~/Views/Shared/Menu.vbhtml"}
My Controller code:
using SportsStore.Domain.Abstract;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
namespace SportsStore.WebUI.Controllers
{
public class NavController : Controller
{
private IProductRepository repository;
public NavController(IProductRepository repo)
{
repository = repo;
}
public PartialViewResult Menu()
{
IEnumerable<string> categories = repository.Products
.Select(x => x.Category)
.Distinct()
.OrderBy(x => x);
return PartialView(categories);
}
}
}
My _Layout.cshtml file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
<title>#ViewBag.Title</title>
</head>
<body>
<div class="navbar navbar-inverse" role="navigation">
<a class="navbar-brand" href="#">SPORTS STORE</a>
</div>
<div class="row panel">
<div id="categories" class="col-xs-3">
#Html.Action("Menu", "Nav")
</div>
<div class="col-xs-8">
#RenderBody()
</div>
</div>
</body>
</html>

Where is your Menu view located?
If you don't explicitly define what your View is called, MVC will take the initiative and assume it's named the same as your Action, so in this case, you need to have a Menu.cshtml file in one of the following locations :
~/Views/Nav/Menu.cshml
~/Views/Shared/Menu.cshtml
Or if it is named anything other than Menu.cshtml, you may want to consider specifying that within your code :
// This assumes your partial view is named "_Menu.cshtml"
return PartialView("_Menu",categories);

#Rion Willimas, you are correct. The book I was following had a small mistake. In the next chapter, it had me create a Menu.cshtml file and then it all rendered fine.
Menu.cshtml below:
#model IEnumerable<string>
#Html.ActionLink("Home", "List", "Product", null,
new { #class = "btn btn-block btn-default btn-lg"})
#foreach (var link in Model)
{
#Html.RouteLink(link, new
{
controller = "Product",
action = "List",
category = link,
page = 1
}, new
{
#class = "btn btn-block btn-default btn-lg"
})
}

Related

Is it possible to display multiple partial view one below row-wise in single _Layout.cshtml?

I have a situation where i wish to render 2 partial views in single layout.cshtml one below another. Each partial view belongs to separate controller. I processed it using 2 different approach, the first one which i wanted it to work didn't worked out.
What i wanted it is to have partial view controller of categoris1 (see div-id below in layout.cshtml) and then below it display partial view of categoris2 div.
let's say this is my _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - ABCD</title>
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.min.css" rel="stylesheet" />
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
#Html.ActionLink("TitleName", "Index", "Files", new { area = "" }, new { #class = "navbar-brand" })
</div>
</div>
</div>
<div class="row panel">
//My first view should be displayed here
<div id="categoris1" class="col-lg-3">
#Html.Action("DispatchedProducts", "DispatchedProducts")
</div>
//Second view should be displayed here just below first one
<div id="categoris2" class="col-lg-3">
#Html.Action("DisplayUnDispatchedProducts", "UnDispatchedProducts")
</div>
<div class="col-lg-8">
#RenderBody()
</div>
<hr />
<footer>
<p>© #DateTime.Now.Year - My MVC Application</p>
</footer>
</div>
</body>
</html>
This results in displaying of the categoris1 div controller view only when i run application (but not categoris2 partialview)and categoris2 div partial view is displayed at other url (when i write path to controller and view in browser) and what i wanted it is to display on same page just below categoris1 .
My next approach which worked was i just kept this categoris2 div (line below) in the partial view of 'DispatchedProducts' at the bottom of DisplayDispatchedProducts.cshtml and it displayed exactly what i expected.
<div id="categoris2" class="col-lg-3">
#Html.Action("DisplayUnDispatchedProducts", "UnDispatchedProducts")
</div>
Complete DisplayDispatchedProducts.cshtml something like this:
#model IList<ABC.Models.Product>
#{
ViewBag.Title = "First view";
}
<div class="col-md-10">
<h2>Dispatched Items</h2>
<div class="form-group">
<label class="col-md-2 control-label">Dispatched Items</label>
<table>
#foreach (var item in Model)
{
<tc>
<td>
<img src=#item.ProdUrl height="100" width="100" />
</td>
</tc>
}
<hr />
</table>
</div>
</div>
and DisplayDispatchedProducts controller has method like this (similar is other controller and partial view with same return types but different queries) :
public PartialViewResult DisplayDispatchedProducts()
{
productDispatched = uow.ProductsRepository.GetProductWithOrder().ToList();
return PartialView(productDispatched);
}
But i want to move with the first approach to have call to both partial views in just _Layout.cshtml file like i mentioned above. Which i expected to display both in a row below each other. Is it feasible to happen ? How to make it work ?
Please let me know if any other info needed
Have you tried calling Html.RenderPartial or Html.RenderAction?
RenderPartial(String partialViewName)
RenderAction(String actionName, String controllerName, Object routeValue)
There are other overrides for each of these methods depending on which version of the framework you are using.

Controller to View via ViewData

This is View File here Displaying error for student in list
#model IEnumerable<Controller2View.Models.Students>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div class="container">
<div class="btn btn-default">
<ul class="list-group">
#foreach (var std in ViewData["StudentData"] as List<Students>)
{
<li class="list-unstyled">
std.StudentName
</li>
}
</ul>
</div>
</div>
</body>
</html>
This is Controller file which have a list defined and viewdata for transferring data from controler to View. Model also defined well but dont know whu its not working.
public ActionResult Index()
{
List<Students> studentList = new List<Students>() {
new Students(){ StudentId=1, StudentName="Steve"},
new Students(){ StudentId=2, StudentName="Bill"},
new Students(){ StudentId=3, StudentName="Ram"}
};
ViewData["StudentData"] = studentList;
return View(studentList);
}
Would be good to know what exactly is not working. But still 2 things:
Either use the view with a model or with ViewData.
I guess you get a list of 3 items with "std.StudentName", that's because it must read #std.StudentName
Use below code in controller
public ActionResult Index()
{
var studentList = new List<Students>() {
new Students(){ StudentId=1, StudentName="Steve"},
new Students(){ StudentId=2, StudentName="Bill"},
new Students(){ StudentId=3, StudentName="Ram"}
};
return View(studentList);
}
Now, In View use below code
#model IEnumerable<Controller2View.Models.Students>
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
<div class="container">
<div class="btn btn-default">
<ul class="list-group">
#foreach (var std in Model)
{
<li class="list-unstyled">
std.StudentName
</li>
}
</ul>
</div>
</div>
</body>
</html>
Hopefully it will works as I am using model directly instead of casting it into list.

Class 'App\Http\Controllers\Flash' not found in Laravel 5.1

I tried lot,googling even took help from laracast.com/discuss but could not solve the issue. why the session flash is not working? please drop your suggestion. Here is my code of all_controll.php
<?php
namespace App\Http\Controllers;
use DB;
use App\Quotation;
use App\Model\students;
use Illuminate\Http\Request;
//use Auth;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests;
use App\Http\Controllers\Session;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Redirect;
class all_control extends Controller
{
public function index()
{
return view('index');
}
public function insert_students(Request $request)
{
$std = new students();
$std->name = $request->input('name');
$std->email = $request->input('email');
$std->save();
return redirect('/index');
}
public function getform()
{
return view('form');
}
public function postform()
{
$roll = Input::get('roll');
$ct_number = Input::get('ct');
DB::table('test')->insert(array(
'name' => $roll,
'age' => $ct_number
));
Flash :: Session ("key",
"You have done successfully!!!!");
//Session::flash('message','You have done successfully!!!!');
return Redirect::route('getform');
//return redirect('/index');
}
}
and my form.blade.php code is given below
<!DOCTYPE html>
<html lang="en">
<head>
<title>Title</title>
<meta charset="UTF-8">
<meta name=description content="">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
<h1>Form</h1>
<h3>
<?php
if(Session::has('key')){
echo Session::get('key');
}
?>
</h3>
<form action="{{ URL::route('postform') }}" method="post" role="form">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<legend>Form Title</legend>
<div class="form-group">
<label for="">name</label>
<input type="text" class="form-control" name="roll" id="roll" placeholder="Input...">
</div>
<div class="form-group">
<label for="">Marks of Physisc CT</label>
<input type="number" class="form-control" name="ct" id="ct" placeholder="Input...">
</div>
<button type="submit" class="btn btn-primary">Hit the Button</button>
</form>
</div>
</body>
</html>
You can use the built in redirect() helper which will flash the data to the session by using ->with().
public function postform(Request $request)
{
$roll = $request->roll;
$ct_number = $request->ct;
DB::table('test')->insert([
'name' => $roll,
'age' => $ct_number
]);
return redirect('index')->with('key', 'You have done successfully');
}
SIDENOTE:
Inject Request into your method and use it instead of Input. Input was used in laravel 4 while injecting the Request class is the recommended way in laravel 5.1
I have also faced same issue with you.
My solution is to include use Flash; on top of the controller that you wanted to use the Laracasts Flash plugin.
Hope this helps.
return redirect()->route('posts.index')->with('success_msg', 'Post deleted successfully');
Here Success_msg is used to display msg on redirected page.

ASP.Net MVC Popup Message after submit button clicked

I'm new to MVC so I'm not completely sure that I have the model tied into the controller and view as it should be. I'm trying to have a message pop up after an error has occured. In this case the error occurs after the submit button has been clicked.
The view...
#if (ViewBag.Message != null)
{
<script>
$(document).ready(function () {
alert('#ViewBag.Message');
});
</script>
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Guru Dental: Request Demo</title>
<!-- CSS -->
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400italic,400">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Droid+Sans">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Lobster">
<link rel="stylesheet" href="~/Content/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="~/Content/assets/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="~/Content/assets/css/animate.css">
<link rel="stylesheet" href="~/Content/assets/css/magnific-popup.css">
<link rel="stylesheet" href="~/Content/assets/flexslider/flexslider.css">
<link rel="stylesheet" href="~/Content/assets/css/form-elements.css">
<link rel="stylesheet" href="~/Content/assets/css/style.css">
<link rel="stylesheet" href="~/Content/assets/css/media-queries.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- Favicon and touch icons -->
<link rel="shortcut icon" href="~/images/favicon.ico" type="image/x-icon">
<link rel="icon" href="~/images/favicon.ico" type="image/x-icon">
</head>
<body>
<!-- Top menu -->
<nav class="navbar" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#top-navbar-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<br>
<img class="logo-size" src="~/images/guru-dental-slogan.png" alt="">
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="top-navbar-1">
<ul class="nav navbar-nav navbar-right">
<li><a href='#Url.Action("Index", "Home")'><br><br>Home</a></li>
<li>
<a href='#Url.Action("Contact", "Home")'><br><br>Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Page Title -->
<div class="page-title-container">
<div class="container">
<div class="row">
<div class="col-sm-12 wow fadeIn">
<h1>Demo Request</h1>
</div>
</div>
</div>
</div>
<!-- Contact Us -->
<div class="contact-us-container">
<div class="container">
<div class="row">
<div class="col-sm-7 contact-form wow fadeInLeft">
#using (Html.BeginForm("DemoSubmit", "CRM", FormMethod.Post))
{
<h2>Rep Details</h2>
<div class="form-group">
<label for="contact-firstname">HSD Rep Code</label>
<input type="text" name="hsdrepcode" placeholder="Enter your HSD Rep code..." class="contact-name" id="contact-name">
</div>
<div class="form-group">
<label for="contact-lastname">Rep First Name</label>
<input type="text" name="hsfirstname" placeholder="Enter your Rep first name..." class="contact-name" id="contact-name">
</div>
<div class="form-group">
<label for="contact-lastname">Rep Last Name</label>
<input type="text" name="hslastname" placeholder="Enter your Rep last name..." class="contact-name" id="contact-name">
</div>
<h2>Doctor Details</h2>
<div class="form-group">
<label for="contact-currentlocation">Doctor's First Name</label>
<input type="text" name="firstname" placeholder="Enter your doctor's first name.." class="contact-subject" id="contact-subject">
</div>
<div class="form-group">
<label for="contact-currentlocation">Doctor's Last Name</label>
<input type="text" name="lastname" placeholder="Enter your doctor's last name..." class="contact-subject" id="contact-subject">
</div>
<div class="form-group">
<label for="contact-currentlocation">Doctor's Phone Number</label>
<input type="text" name="phonenumber" placeholder="Enter your doctor's phone number..." class="contact-subject" id="contact-subject">
</div>
<div class="form-group">
<label for="contact-currentlocation">Doctor's E-mail</label>
<input type="text" name="emailaddress" placeholder="Enter your doctor's e-mail..." class="contact-subject" id="contact-subject">
</div>
<button type="submit" class="btn">Submit</button>
}
</div>
The controller...
public ActionResult RequestDemo()
{
return View();
}
[HttpPost]
public ActionResult DemoSubmit(LeadInfo leadInfo)
{
string salesEmail = CRMModels.GetNextSalesEmail();
ViewBag.Message = CRMModels.AddLeadToCRM(leadInfo);
if (ViewBag.Message == null)
{
EmailModels.SendEmailForLead(leadInfo, salesEmail);
return RedirectToAction("Index", "Home");
}
else
return RequestDemo();
}
}
The model...
if (hsdRepId != Guid.Empty)
{
lead.Attributes["ree_hsdrepresentative"] = new EntityReference("ree_henryscheinrepresentative", hsdRepId);
service.Create(lead);
}
else
{
message = "Invalid HSD Representative Code";
}
return message;
In the DemoSubmit function, if there is a message to display, I need to go back to the view to display it. How do I do that? I tried to do with a redirect but that just gives me a new page with none of the data that was entered in and it didn't display the message.
Thanks,
Gary
On controller once you got error you can add error message to modalState
ModelState.AddModelError("", "Invalid HSD Representative Code");
and to pop the error alert you can use html extension method to pop the message
public static HtmlString PopAlert(this HtmlHelper htmlHelper, string alertType = "danger",
string heading = "")
{
if (htmlHelper.ViewData.ModelState.IsValid)
return new HtmlString(string.Empty);
var sb = new StringBuilder();
sb.AppendFormat("<div class=\"alert alert-{0} alert-block\">", alertType);
sb.Append("<button class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">×</button>");
if (!heading.IsNullOrWhiteSpace())
{
sb.AppendFormat("<h4 class=\"alert-heading\">{0}</h4>", heading);
}
sb.Append(htmlHelper.ValidationSummary());
sb.Append("</div>");
return new HtmlString(sb.ToString());
}
On view you simply call the Html extension method like this
#Html.PopAlert()
hope this will help you :)
You have a number of problems with your code, in particular the fact you not binding any controls to you model so returning the view will always display empty controls. You should also include validation attributes on you properties to prevent posting and saving potentially bad data. Your view is also generating invalid html (lots of duplicate id attributes) and <label> tags which are not really labels (clicking on them wont set focus to the associated control because you don't associate them with a control.
Based on your view, your LeadInfo class looks something like (suggested attributes added)
public class LeadInfo
{
[Display(Name = "HSD Rep code")]
[Required(ErrorMessage = "Please enter your HSD Rep code")]
public string hsdrepcode { get; set; }
[Display(Name = "Rep first name")]
[Required(ErrorMessage = "Please enter your Rep first name")]
public string hsfirstname { get; set; }
.....
[Display(Name = "Doctor's e-mail")]
[Required(ErrorMessage = "Please enter your doctor's e-mail")]
[EmailAddress]
public string emailaddress{ get; set; }
}
You GET method should then be
public ActionResult RequestDemo()
{
LeadInfo model = new LeadInfo();
return View(model);
}
and the view should then strongly typed html helpers to bind to your properties and to display validation errors
#model LeadInfo
....
#using(Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true) // this is where you custom error message will be displayed
#Html.LabelFor(m => m.hsdrepcode) // displays the text associated with the DisplayAttribute and is associated with the following textbox
#Html.TextBoxFor(m => m.hsdrepcode, new { placeholder="Enter your HSD Rep code...", #class="contact-name"})
#Html.ValidationMessageFor(m => m.hsdrepcode)
....
<button type="submit" class="btn">Submit</button>
}
You should also include the following scripts (preferably using #Scripts.Render() and the bundling and minification features of MVC)
jquery-{version}.js
jquery.validate.js
jquery.validate.unobtrusive.js
You should also be using layouts (master pages)
The post method is then
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RequestDemo(LeadInfo model) // not sure why you would change the name of the method?
{
if(!ModelState.IsValid)
{
return View(model); // return the view to fix any validation errors
}
string errorMessage = CRMModels.AddLeadToCRM(leadInfo);
if (errorMessage == null)
{
string salesEmail = CRMModels.GetNextSalesEmail();
EmailModels.SendEmailForLead(leadInfo, salesEmail);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", errorMessage);
return View(model);
}
}
Its not clear what the error message you want to return is, but you code suggests it might be associated with the hsdrepcode property, in which case, modify the code to associate the error with a particular property
ModelState.AddModelError("hsdrepcode", errorMessage);
Side note: Most of your code is ignoring the benefits of using MVC, to the point you may as well not use it. I recommend you go the the MVC site and work through the tutorials,

Ajax missunderstanding, or an error?

Can you please explain me how should i use Ajax properly.
I have an easy example in Asp.Net MVC:
This is my layout view
<html>
<head>
//scripts
</head>
<body>
<div id="header">
<div class="logo">
<img id="LogoImg" src="http://www.ruralcomshow.com/wpontent/uploads/2014/06/Midwest-Data-Center-Logo-175x75.png" />
</div>
</div>
<div class="wrapper">
<div class="left-side">
//some navigation
</div>
<div id="right-side">
#RenderBody()
</div>
</div>
<div id="footer">
<div class="clearfix">
//some footer
</div>
</div>
</body>
</html>
This is my controller:
public class HomeController : Controller
{
public PartialViewResult Ajax()
{
return PartialView();
}
public ActionResult Index()
{
return View();
}
}
This is Ajax partial view:
<h2>This is how it's done</h2>
#Html.ActionLink("back :C","Index","Home")
This is Index view:
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#Ajax.ActionLink("Go, go Ajax!", "Ajax", "Home", new AjaxOptions { UpdateTargetId = "right-side", InsertionMode = InsertionMode.Replace})
So, as I understood when i click Ajax ActionLink my whole page should not rerender, and the only thing that should change is div with id "right-side"? So the problem is that the whole page always gets rerendered.
Am I doing something wrong? Or is this a problem of my understanding?
Include jquery and unobtrusive-ajax at the bottom of the page as shown :-
</footer>
#Scripts.Render("~/bundles/jquery")
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
#RenderSection("scripts", required: false)
</body>
</html>

Resources