I am trying to check the model is null OR not but I am not able to solve the issue.
While rendering the main view I have rendered the partial view as follows
Main View
<div class="modal fade" id="surveyPreviewModal" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-labelledby="surveyPreviewLabel" aria-hidden="true">
<div class="modal-lg modal-dialog">
<div class="modal-content" id="surveyPreviewContent">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<h4 class="modal-title" id="surveyPreviewLabel">Survey Preview</h4>
</div>
<div class="modal-body" id="surveyPreviewBody">
#Html.Partial("_surveyPreview")
</div>
</div>
</div>
</div>
and in partial view I have function as below
#model LMS_TraineeSurveyPaginationViewModel
<script type="text/javascript">
function SurveyPreview(){
var surveyQuestionViewModel = #Html.Raw(Json.Serialize(Model.SurveyQuestionsViewModel.ToArray()));
var surveyQuestionOptionChoideViewModel= #Html.Raw(Json.Serialize(Model.SurveyQuestionOptionChoiceViewModel.ToArray()));
$.post('#Url.Action("SurveyPreview", "Survey")', { SurveyID : surveyID,` page : page },
function (data) {
$('#surveyPreviewBody').html('');
$('#surveyPreviewBody').html(data);
SetProgressBar(page,'#(Model==null?0: Model.Pager.TotalPages)');
}).fail(function () {
alert("error in GetTraineeSurvey");
}).success(function () {
});
}
</script>
So while rendering the partial view in this function(SurveyPreview) it is giving the error as model is null and straight away white screen shown. If I haven't called the function which is inside of partial view then why does it checking whether model is null OR not ? it should be whenever I execute function like on button click ?
I have a button on main view from where I am showing the bootstrap modal and on 'show' method of bootstrap modal I am returning the same partial view again to bind the data in ajax call.
Below code is written in partial view
$(document).ready(function () {
$('#surveyPreviewModal').on('show.bs.modal', function (e) {
surveyID = $(e.relatedTarget).attr('data-surveyID');
SurveyPreview(#SurveyPageTypePageNumber.StartPage,null);
});
})
and in controller
public ActionResult SurveyPreview(int SurveyID, int page)
{
------ some code ------
return PartialView("_SurveyPreview",viewModel);
}
Any help on this appreciated !
when you load Partial view using #Html.Partial("_surveyPreview") it required LMS_TraineeSurveyPaginationViewModel to be passed which are not supplied
so to call Partial view you need to write something like
#Html.Partial("_surveyPreview",new LMS_TraineeSurveyPaginationViewModel());
The partial view expects a model of type LMS_TraineeSurveyPaginationViewModel. But you are not passing any model object when rendering partialview from the main view.
In partialview function SurveyPreview() uses Model's properties. Since you are not passing any model object from the main view, Model is coming null in the partial view. That's why you are seeing NullReferenceException.
So you need to make sure that the partial view gets model.
You need to take different approach to render the partial view. You can use Html.Action to call the Action method which will return the partial view and render in the main view.
Replace following line in your main view
#Html.Partial("_surveyPreview")
with
#Html.Action("SurveyPreview", new { SurveyID = "<<somesoveryId>>", page = "<<somepage>>"})
This way I will call SurveyPreview action of the controller with the provided parameters and it will return the partial view with model and it will be rendered.
I am not sure of the what values to be passed in SurveyID and page parameters so I have placed placeholders there. You need to put appropriate values over there.
Related
I have a Modal with 2 Tabs and I have an input on one of them. I need to pass the value of that input to the controller after clicking the search button. After that, the modal should stay. How can i pass the parameter to the controller without closing the modal?
<div class="modal-body">
#using (Html.BeginForm("SearchKuerzel", "Home"))
{
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="USZ-Kürzel" id="MyParameter" aria-label="USZ-Kürzel" aria-describedby="basic-addon2">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit">Mitarbeiter suchen</button>
</div>
</div>
}
</div>
You can either use javascript like #3xGuy has said or use jquery such as below:
$('#MyParameter').val();
to get the value and then use ajax to send information to the controller. From here can do whatever you want in the controller and just return Json such as below from the controller.
return Json(new {success = //true or false or whatever});
EDIT:
Once you have done what you want in the controller, you can return the value like I have returned the variable 'success' in the code above. In the result section of the ajax request you can get the data from the controller such as this:
//the rest of the ajax request
success: function(result)
{
//Change the value of html element to success in this case
$('#//id of the element').text(result.success)
}
EDIT 2:
To return two Json strings do as above but add another return such as:
return Json(new {string1 = //whatever, string2 = //whatever});
And in the ajax access them like:
success:function(result)
{
var return1= result.string1;
var return12 = result.string2;
}
I have a problem where I have a form in a Html.RenderAction and after submitting the form I have to reload the parent but I keep getting "Child actions can not perform redirect actions". So how can I solve it without Ajax etc.
In my parent I have:
#{
var UserReviewExist = Model.Reviews.FirstOrDefault(x => x.AspNetUser.UserName == Name.AspNetUser.UserName);
}
#{if (UserReviewExist == null)
{
Html.RenderAction("ReviewCreate", "Reviews", new { BookID = Model.Id });
}
}
My RenderAction View contains this:
#model Trigger_Happy_Bunnies.Models.Review
#{
Layout = null;
}
#{
if (true)
{
Trigger_Happy_Bunnies.Models.Review newReview = new Trigger_Happy_Bunnies.Models.Review();
<div style="border:1px black">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
and ends with
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
}
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And lastly I have this in my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ReviewCreate([Bind(Include = "Id,BookId,UserId,Text,Title,Rating,IsActive,IsReported,ReportedBy,ReportReason,ModifiedDate,ModifiedBy,CreatedDate")] Review review)
{
if (ModelState.IsValid)
{
db.Reviews.Add(review);
db.SaveChanges();
return View("~/Views/Reviews/ReviewCreate.cshtml");
}
ViewBag.UserId = new SelectList(db.AspNetUsers, "Id", "Email", review.UserId);
ViewBag.BookId = new SelectList(db.Books, "Id", "UserId", review.BookId);
return PartialView();
}
So how can I update the parent view when submitting the form?
I'm not sure what your issue is here. A child action merely dumps its response into the view. So at the end of the day, whether you used a child action, a partial or just plopped the code right in the view, you just have a one HTML document that includes a form.
Calling Html.BeginForm with no parameters says basically that it should use the current action, but even in the context of child action, that's still going to be the main action being rendered. So, your form will post to that main action, not your child action.
That's how it should be. You cannot post to a child action, because that makes no sense in the context of a web page. Technically, you can as long as it's not marked as [ChildActionOnly], but the entire page will change to the partial view that's returned as the response, sans layout. If you want to replace just the area that was rendered via the child action, you must submit an AJAX request that returns the partial response and manually replace the appropriate node in the DOM with that.
In other words, that's why a child action can't redirect. It's not a true action and it hasn't been routed to. It's not rendered until the response preparation phase, and by that point, there's already data in the response, preventing any changes, like a redirect. If you need to redirect after the post of the form, you should have that already in place, just make sure your main action has a version that handles post, and redirect from there.
I have the following div in my view:
<div id="review">
REVIEW:
<p>
<%:ViewData["Review"]%>
</p>
<input name="submit" id="submit" type="submit" value="OK"/>
</div>
How can I set DIV visibility to visible inside of controller when a certain button is clicked?
This is a code fragment in my controller:
public ActionResult Index(EsafeModel model,string submit, string create)
{
if (button.Equals("Create"))
{
ViewData["Review"] = ESafeData.CreateReview(eSafe);
}
else if (button.Equals("OK"))
{
if (ESafeData.Create(eSafe))
{
ViewData["Message"] = "E-Safe data created!!!";
}
}
}
You can't do this directly as div is on client side and the controller is server side.
What you can do is have a property in your model which is bound to view .This can have the value of visibility attribute for div and then you can assign it using server tags to div
Below is a sample code snippet
<div id="elementid" style="visibility:'<%=Model.Visible %>'"/>
On the click of button you can return the same view and model but this time model will have Visible ="hidden"
I am currently using knockoutjs with one of my MVC applications.
The Layout template looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="container-fluid head-content">
<div class="row">
<div class="col-xs-6">
<img class="img-responsive" src="~/Images/logo.jpg" />
</div>
<div class="col-xs-3">
<a class="block" href="#" style="display: none" data-bind="visible: showBack, click: goBack">
<div class="block-text">
<h4>Back</h4>
</div>
</a>
</div>
<div class="col-xs-3">
<a class="block" href="#" style="display: none" data-bind="visible: showHome, click: navigateToHome">
<div class="block-text">
<h4>Home</h4>
</div>
</a>
</div>
</div>
</div>
<div class="container-fluid body-content">
#RenderBody()
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
</html>
and my Index partial looks like this:
#Html.Partial("_Login")
#Html.Partial("_Home")
#Html.Partial("_CutLengths")
#Html.Partial("_MoveStock")
#section scripts {
#Scripts.Render("~/bundles/knockout")
#Scripts.Render("~/bundles/app")
}
My problem is that depending on which page I am on, I would like to use the back button to go to another page. For example, if I am on cutLengths I would want the back button to take me home.
My app.viewmodel.js has a method which looks like this:
// Other operations
self.addViewModel = function (options) {
var viewItem = {},
navigator;
// Add view to AppViewModel.Views enum (for example, app.Views.Home).
self.Views[options.name] = viewItem;
// Add binding member to AppViewModel (for example, app.home);
self[options.bindingMemberName] = ko.computed(function () {
if (self.view() !== viewItem) {
return null;
}
return new options.factory(self, dataModel);
});
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () {
self.view(viewItem);
};
}
// Add navigation member to AppViewModel (for example, app.NavigateToHome());
self["navigateTo" + options.name] = navigator;
};
What I would like to do is pass a string from the ViewModel I am currently viewing which when the back button is pressed will know to direct me to the right ViewModel.
Is it possible to do this?
I hope I have explained it well, if I haven't please ask and I will try harder :D
You can use either ViewData or ViewBag for passing data from the controller to view. So one option is to just add a few dynamic properties to ViewBag for current view model and prior view model.
ViewData is a dictionary of objects that are stored and retrieved using strings as keys.
ViewBag uses the dynamic feature that was introduced into C# 4.It allows an object to have properties dynamically added to it. I would use this for passing your view model state around.
Neither provide compile time checking, which is the beauty of them, you can add anything you want. With that said it’s always good practice to use strongly typed view models over ViewBag and ViewData.
If you'd rather put something in your view model instead of adding properties to ViewBag, than just add another property in each view model called PreviousViewModel and populate it any time you use the model.
Examples using ViewBag or ViewData
ViewData["LastViewModel"] = "CutLengths";
ViewBag.LastViewModel = "CutLengths";
Access your ViewBag in the Views is no problem, they have global scope. ViewBag is like a global variable that you can attach anything to-- so I'd use them judiciously-- maybe some type of a singleton application manager would be a better design.
Hope this helps
I have solved this now. First I changed my HTML
<div class="col-xs-3">
<a class="block btn-back" href="#" data-bind="visible: showBack, click: goBack"></a>
</div>
<div class="col-xs-3">
<a class="block btn-home" href="#/home" data-bind="visible: showHome"></a>
</div>
Then I edited my app.viewmodel.js file and added these
// Data
self.back = ko.observable(null);
// UI state
self.showBack = ko.observable(true);
self.showHome = ko.observable(true);
self.goBack = function () {
if (self.back()) {
window.location.href = self.back();
} else {
window.history.back();
}
self.back(null); // Reset
};
self.setBackUrl = function (url) {
self.back(url);
}
Then on my addViewModel navigate function, I added this:
if (typeof (options.navigatorFactory) !== "undefined") {
navigator = options.navigatorFactory(self, dataModel);
} else {
navigator = function () { // This is our navigator function which sets the current view
self.showBack(true);
self.showHome(true);
self.error(null); // Reset errors
self.view(viewItem);
};
}
And then in my other view models, I just make a call to setBackUrl like this:
app.setBackUrl("#/cut-lengths");
And if I want to hide my buttons, that is easy too. I just create a navigatorFactory on the viewModel like this:
app.addViewModel({
name: "Home",
bindingMemberName: "home",
factory: HomeViewModel,
navigatorFactory: function (app) {
return function () {
app.showBack(false);
app.showHome(false);
app.error(null);
app.view(app.Views.Home);
}
}
});
In my ASP.NET MVC 5 web site i have a devexpress navbar with multiple itens, each item have a single unique controller, always when i click on a item the Index action of the corresponding controller is called.
public ActionResult Index()
{
//Load large data and return it into a gridview.
}
While im loading this data i would like to show a loading panel but i dont know where i can do it using in mvc, in aspnet webforms its easier to do something like that.
Any MVC expert could help me with this?
Inside your view you suppose to use am Ajax Form, and to point to your LoadingElementId in it's definition.
Here is an example:
#using (Ajax.BeginForm("FilterNews", "News", null,
new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "container", LoadingElementId = "custom-loading" }))
{
<div id='container'>
//Your helpers #Html.TextBoxFor(x => x.....) or render a partial
</div>
}
<style>
.loading{
position:absolute;
width:100%,
height:100%,
top:0,
left:0,
background:white,
}
</style>
<div id="custom-loading" class="loading">Loading..Please wait...</div>
Also if you want to display a Loader for every XHR Call u may set a binder on ajaxSend event like this :
<div id="ajax-loader-element">
<img src="#Url.Content("~/Content/Images/ajax-loader.gif")"/>
</div>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery(document).bind("ajaxSend", function () {
jQuery('#ajax-loader-element').show();
}).bind("ajaxComplete", function() {
jQuery('#ajax-loader-element').hide();
});
});
</script>