Force Save Sitefinity Widget MVC Controller Property - c#

I am making a Sitefinity Widget using an MVC Controller. The widget shows and all that, no problem there. What I would like to do is save data for the widget in JSON form in a hidden property. I know how to make the property hidden via an attribute but I want to know how to POST data to my controller and set a property on the controller which will be saved in sf_control_properties table. Normally controller properties only get saved here when editing a widget's properties and clicking save in Admin UI. My control will have two modes (User view and Admin view). I am not making a custom designer via the edit modal popup. I am showing the design view while in page design mode on the widget itself. I have a save button that will do a POST to the controller on the backend. I want it so set a property and then persist it to the sf_control_properties table like a normal edit->modal->Save would do. I know I could connect directly to SQL and write the value but is there a better way to force a Widget Property to save in an MVC Controller than SQL brute force? Here is an example of my controller setup.
[ControllerToolboxItem(Name = "MyWidget", Title = "My Widget", SectionName = "Dashboard")]
public class MyWidgetController : Controller
{
public string Title { get; set; }
public string CssClass { get; set; }
public string CustomData {get;set;} //JSON string data
public ActionResult Index()
{
var viewModel = this.CustomData.FromJson<MyWidgetViewModel>();
return View(ViewModel);
}
[HttpPost]
public ActionResult Save(MyWidgetModel model)
{
this.CustomData = model.ToJson();
}
}
So basically when I do an ajax post to this controller I want to set this.CustomData = postModel.ToJson() and persist it to the sf_control_properties table.
I am doing this to avoid making a custom Dynamic Module with my own table, etc. When control loads in normal user view I will convert the this.CustomData property to C# class and use it in my razor view....

Related

Back button Functionality on Review Details page beore the Submit button

I want to show a Review page after the user fill sout all the information but on the review page I need to have a "Back" button which should take the user back tot he previous page with the same state and all the changes that they have made. What is the best way of achieving this ? I coded the review page on a different view but then the back is clicked the state of the page with all the changes I lost.
I have tried trying to code the view in another view page
The best way is that you support the parameters in your View:
For example:
public class MyClass
{
public IEnumerable<string> MyProperty { get; set; }
}
And in the Controller:
public ActionResult Index()
{
// Create your model and set the values
var myModel = new MyClass
{
MyProperty = new List<string> { "First Value", "Second Value" }
};
// Return the model back to your view for access using #Model
return View(myModel);
}
You have to generate your own model for the form completion, and then pass all the objects (Ideally just one with many attributes) from the review page to the form filling page and vice-versa.

Dynamically add Views in ASP.NET MVC

I was originally developing a project for WPF, using MVVM, which had the benefit of allowing me to populate a list of views that I wanted available. Each view had a "Next" button that would progress to the next view in the list.
However, now I am trying to do the same in ASP.NET MVC. This is my first time using MVC, but I have an XML file, from which I need to generate this UI. These views, which are chosen from the script, also have components in them that are dynamic -- sometimes ViewA might need 3 "input views" nested in it, sometimes it might need 1.
I was achieving that before with ListBox, ItemsSource, and DataTemplate. So my question is this: how can I dynamically populate which views to display, and (more importantly) how can I dynamically fill those views with x number of control A, and y number of control B?
First off, a high-level overview of the project structure...
YourProjectName
Controllers
ProductController.cs
Models
ProductViewModel.cs
Views
_ProductPartial.cshtml
ListProducts.cshtml
ProductViewModel.cs
public class ProductViewModel
{
public string Name { get; set; }
public string Description { get; set; }
}
ProductController.cs
public class ProductController : Controller
{
public ActionResult Index()
{
// Create your model (this could be anything...)
var model = new List<ProductViewModel>
{
new ProductViewModel { Name = "Apple", Description = "A red apple" },
new ProductViewModel { Name = "Orange", Description = "An orange orange" }
};
// Return the main view and your model
return View("ListProducts", model);
}
}
_ProductPartial.cshtml
#model YourProjectName.Models.ProductViewModel
<h1>#Model.Name</h1>
<p>#Model.Description</p>
ListProducts.cshtml
#model System.Collections.Generic.List<YourProjectname.Models.ProductViewModel>
#foreach (var product in Model)
{
Html.Partial("_ProductPartial", product)
}
Summary
Now if you request that controller action (localhost/Product/Index or whatever it ends up being for you), the controller will create the model, render the parent view, and the parent view will render as many of the product partial views as necessary depending on the product model collection we defined in the controller. Views and partial views don't require models, but I imagine you will be using a model class of some sort to help you determine what/where/how many partial views to render in your parent views. This is about as basic as it gets but it should get you started in using partial views.

How to validate multiple ViewModels in single view by condition using ModelState.IsValid

I have a problem with validation of one view with multiple ViewModels. My situation is, that I have one Basic form, which is same for lot of pages. By ID parameter, I render new external fields to this Basic form. These external fields are type of ActionResult, using own ViewModel and own Controller. In Main controller on Post action I want to control if ModelState.IsValid, but I have problem - it validate all ViewModels of all external fields, but I want to validate only ViewModel of active external fields (and Basic form too).
It looks like this:
ViewModel of all view models
public class AllFieldsVm
{
public BasicFormVm BasicFormVm { get; set; }
public ExternalFieldXyVm ExternalFieldXyVm { get; set; }
public AnotherExternalFieldVm AnotherExternalFieldVm { get; set; }
}
In controller of external fields I create new instance of AllFieldsVm and in this create new instance of ExternalFieldXyVm (if I need, I prefill these fields). This I render whitout layout like partial view (using #{Html.RenderAction("Action", "Controller", new {#someOptionalData = value});} ), when some condition is true.
In controller of Basic form on Post action I have something like this and I want to use something like this code if (ModelState.IsValid(model.BasicFormVm) && ModelState.IsValid(model.ExternalFieldXyVm)):
[POST("someurl-id{someId}")]
public ActionResult SaveFormData(int someId, AllFieldsVm model)
{
//Here I want something like
//if (ModelState.IsValid(model.BasicFormVm) && ModelState.IsValid(model.ExternalFieldXyVm)) or something like that...
var se = new SomeEntity();
se.property1 = model.property1;
se.property2 = model.property2;
using (var dbc = _db.Database.BeginTransaction())
{
try
{
_db.Add(se);
_db.SaveChanges();
//My Condition - when save external data
if (someId == (int) MovementTypes.SomeEnumInt)
{
var rd = new ExternalFieldEntity
{
PropertyA = se.property0,
PropertyB = Convert.ToDateTime(model.ExternalFieldXyVm.SomeExternalFieldName)
};
_db.Add(rd);
_db.SaveChanges();
}
dbc.Commit();
}
catch (Exception)
{
dbc.Rollback();
}
}
return RedirectToAction("Action", "Controller");
}
So, my question is, how can I validate ExternalFieldXyVm separatly based on some conditions?
Is it possible, or I have to create all own validators, without using basic DataAnnotations or FluentValidation? I have no experience with these types of forms, so please be patient...
Thanks to all for help!!
Great, I got it. I play with this for two days, don't know how it is possible that I didn't see that.
Result is: When view with own view model which is included in main viewmodel, isn't rendered into view, this viewmodel is not validate on post action. So my Basic form is validate everytime, and ExternalFields are validate only when are rendered. So sorry, for so stupid question....

Put value from view in viewBag

I have a hidden field in my HTML view
<%:Html.HiddenFor(model=>model.ContactId) %>
I want to put this value in viewBag so that I can use it in controller. How to do that? Also, how will I access this in controller?
You don't have the notion of postback in ASP.NET MVC and the ViewBag is available to you to deliver data to the view, but not to transfer data back and forth between the view and the controller.
If your hidden input is in a form then upon posting the form the new value would be accessible via model.ContactId.
Example:
// Model
class TestModel
{
public string ContactId { get; set; }
}
//Controller
[HttpPost]
public ActionResult Edit(TestModel model)
{
string newId = model.ContactId;
}

Hidden form fields not appearing in MVC Model after post-back

I have a new MVC 4 Application with a fairly basic View/Controller. The associated Model contains a couple properties that I've mapped to Hidden form fields. When the Page renders the first time (e.g. via the HttpGet Action) it all looks fine. But when the form is Post'ed by selecting the Submit button the resulting Model presented to the Action no longer has the Hidden field values set. Here is a walkthrough of the particulars.
Here is a sample of the Model:
public class Application
{
public bool ShowSideBars { get; set; }
}
Here is the initial Controller *Action* (which seems to work fine):
[HttpGet]
public ActionResult Application()
{
var model = Request.ParseFromQueryString<Application>();
model.ShowSideBars = true;
return View(model);
}
This maps to the View as follows:
<fieldset>
#Html.HiddenFor(m => m.ShowSideBars)
...
</fieldset>
This results in the following mark-up to be rendered inside the fieldset:
<input data-val="true" data-val-required="The ShowSideBars field is required." id="ShowSideBars" name="ShowSideBars" type="hidden" value="True" />
Note: I sure wish I knew why MVC has decided to add the '... field is required' content when I didn't flag it as required, but that's for another question
Here is the Action that is called when the form is submitted. At this point the aforementioned property will no longer be set to 'true'.
[HttpPost]
public ActionResult Application(Application application)
{
// Other work done here
return View(application);
}
At present, there are no custom Model Binders. Also, I've tested some other data types and I'm seeing the same thing.
Can someone explain why hidden form values are not being returned? Am I just doing this all wrong?
If you have the property in your model decorated with a ReadOnlyAttribute the value will not be populated back into the model for you. After all, it is read only.
I just had the same problem. The form didn't submitted the hidden property because the model class didn't had a proper getter and setter for that property.
I know that is not the issue you had, just figured it might help other people that will lend in this page.
I cannot reproduce the issue (ASP.NET MVC 4 Beta running on VS 2010 .NET 4.0).
Model:
public class Application
{
public bool ShowSideBars { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Application()
{
var model = new Application();
model.ShowSideBars = true;
return View(model);
}
[HttpPost]
public ActionResult Application(Application application)
{
return Content(application.ShowSideBars.ToString());
}
}
View:
#model Application
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.ShowSideBars)
<button type="submit">OK</button>
}
When I submit the form, the model binder correctly assigns the ShowSideBars property in the POST action to true.
Note: I sure wish I knew why MVC has decided to add the '... field is
required' content when I didn't flag it as required, but that's for
another question
That's because non-nullable types such as booleans are always required. You could stop ASP.NET MVC helpers from emitting HTML5 data-* client side validation attributes for them by putting the following line in Application_Start:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
I think the fields MUST be within the form html tags for the hidden ones to be posted back and not ignored
try this:
public class Model
{
[ScaffoldColumn(false)]
public bool InvisibleProperty { get; set; }
}
more info here (ScaffoldColumn(bool value) vs HiddenInput(DisplayValue = bool value) in MVC)
In my case it was because I had declared a field instead of a property:
public BaseController.Modes Mode;
doesn't work. But:
public BaseController.Modes Mode { get; set; }
works. The default model binder only works with properties.
I kid you not, this is another reason it could happen.
My form had the same field in it twice. The other field was actually not in the form, but that doesn't matter.
Run this jQuery in the developer console to see how many elements come back:
$("[id$=PropertyName]"); // Search for ids ending with property name.
Example:
For me, in Core 6 the solution was removing [Editable(false)] attribute from the model class Id property which I wanted to tunnel through get/post as a hidden form field. In .Net 4.8 it was not a problem.

Categories