I've found myself working on a .Net MVC3 project and sorely missing having Formtastic available in my rails apps.
Are there any good .Net MVC replacements for Formtastic?
I suggest using MVC3s HTML Helpers.
#model mynspace.MyModel
#Html.EditorForModel()
This html helper generates editor fields for every field in your model, choosing the most likely option. Editing the Editor template, you can change the way it is layed out as well. See this question on changing the template
It can of course be used more customizable by each field with things like:
#Html.Label("Daily Rate")
#Html.EditorFor(model => model.DailyRate)
#Html.ValidationMessageFor(model => model.DailyRate, "Please enter a valid Daily Rate (2 d.p.)")
This can be custom layed out by putting tags around it, i.e. things like <p> or <td>
You can also force an input type using options like:
#Html.TextBoxFor(model => model.DailyRate)
#Html.CheckBoxFor(model => model.DailyRate)
#Html.DropDownBoxFor(model => model.DailyRate, ViewBag.DailyRates)
see here for a full list of options
I have a project called FormFactory that lets you do much of the stuff formastic does http://formfactory.apphb.com/
It transforms model objects into PropertyVm objects, which are a viewmodel for an input basically. You could manually create the PropertyVms if you want.
Related
I am trying to implement a very simple grid with ability to add a new row via a toolbar button. None of the samples provided in the documentation seem to work as expected.
#model Models.MyModel
#{
ViewBag.Title = "Simple Grid";
}
<div class="container-fluid">
<div class="row"></div>
<div class="row">
<div class="col-xs-11">
#(Html.Kendo().Grid<Models.MyModel>()
.Name("myGrid")
.ToolBar(toolbar => {
toolbar.Create().Text("Add New Row");
})
.Columns(columns => {
columns.Bound(p => p.Name).Width(200);
columns.Bound(p => p.Header1).Width(100);
columns.Bound(p => p.Header2).Width(100);
})
.Scrollable()
.Editable(ed => ed.Mode(GridEditMode.InLine).CreateAt(GridInsertRowPosition.Bottom))
.HtmlAttributes(new { style = "height:350px;" })
.DataSource(ds => ds
.Custom()
.Schema(schema => schema
.Model(model => {
model.Id("Id");
model.Field("Name", typeof(string));
model.Field("Header1", typeof(string));
model.Field("Header2", typeof(string));
})
)
)
)
</div>
</div>
</div>
The above is in a simple index.chtml page which uses a layout page and injects all the jQuery and KendoUI scripts.
When the page is loaded get a JS error Unable to get property 'nodeName' of undefined or null reference
Not sure why that happens, but hitting continue, displays an empty grid as expected.
Clicking the "Add new Row" toolbar button results in another JS error (same as above)
Question:
Am I missing a configuration option on the grid? Per documentation, this is supposed to work "out of the box". All I want to achieve is a simple grid which adds a new empty row everytime I click the "Add" button.
While it can be a bit tough to see at first, using the Custom() configuration requires more than just setting the .Schema() configuration. You can refer to samples in in the Custom DataSource documentation article for references to this. Every sample has at least the Transport field defined with a read configuration set so that the DataSource knows where to read the data.
Since you're doing CRUD operations here I also recommend that you set the other transport fields (Create, Read, Update, Destroy) to ensure that you can work with your controller and communicate with your backend properly.
As a quick note, if you search around the Telerik site for the error unable to get property 'nodeName' of undefined or null reference you start to get the hint that this error is due to an incorrect configuration of a component. It's not specific to the Grid, but it does pop up from time-to-time and the issue almost always boils down to configuration options.
Now, to fix this particular issue I'd recommend working with Ajax binding rather than custom binding. Ajax binding is super simple to work with and is perfect for this kind of scenario where you want a simple Grid added to the page without the more advanced configuration that comes from working with a more advanced feature. Plus you can work with your client-side model to set up validation etc., for your server-side (no need to set the schema manually).
Or, alternatively just set the transport field configuration to valid ActionResults or URLs to push information back and forth properly.
When first implementing any new product I always recommend following documentation closely and starting off with the smaller examples and building form there. If you're looking to work with a custom data source then I say start with a bigger configuration and remove pieces until you get the minimal piece that you're looking for.
I may be off my rocker, but since HTML5 came out, does Microsoft have a namespace similar to
using System.Web.Mvc.Html
for HTML5 helpers in your MVC views?
I can't believe they don't have something out for this.... I'm using Visual Studio 13 Update 3.
If they don't, can you simply apply HTML5 tags for the specific model you're using with the View?
So, for example, if you just have an HTML5 input tag as text, can you say something like:
#using exampleModel
#exampleModel.Name
If you say:
#Html.EditorFor(m => m.Name)
... the default editor templates in the latest versions of MVC will render input tags that correspond to the type you provide. For example, if the property is a number you'll get <input type="number"...>.
I'm using AngularJS in my MVC application and trying to use the best of both worlds. I really like how you can in MVC set up your validation logic in your viewmodels and generate client side validation with jQuery validation in your razor views with little effort. I use AngularJS to get the SPA behavior with routing etc, but when I create a razor view that I use to inject into a page with:
<div data-ng-view="data-ng-view"></div>
then the jQuery validation stops working, even though the script files is references on the page where the view is injected. See below for my razor view:
#model BandViewModel
<div data-ng-controller="App.BandCreateCtrl">
<form name="startBandForm">
#Html.ValidationSummary(true)
<br />
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name, new { data_ng_model = "band.Name" })
#Html.ValidationMessageFor(m => m.Name)
<br/>
<input data-ng-disabled="startBandForm.$invalid" type="submit" data-ng-click="createBand(band)" value="Create"/>
</form>
</div>
First of all, IMO using Razor to render your templates is fraught with peril, at best. Generally you want to use static HTML for your page and directive templates, and then retrieve and post data as AJAX to your API. The ASP.NET web API is really good at this, actually. If your underlying model has validation, then bad web API calls will throw an exception, which you can catch in your $http or $resource handler and show to the user. Mixing standard HTTP form posts with AngularJS will be... difficult.
To achieve what you want, I think someone (not me) would have to write the AngularJS equivalent to jQuery Unobtrusive Validation library, which itself is using the jQuery Validate plugin. Not trivial. I personally don't see drop-in Angular validation happening soon, especially since it has more to do with markup and less to do with a JS configuration object.
Possibly you could re-initialize the validation when the view has finished loading using the $viewContentLoaded event. But please don't.
It pains me that everywhere I've looked we get the same replies: "HTML should just be a template". Perhaps, but I'm just not ready to delegate everything to JavaScript
Instead of using the anonymous object for passing the HTML attributes, try using the Dictionary
#Html.TextBoxFor(m => m.Name, new Dictionary<string, object>(){{ "data_ng_model", "band.Name" }})
Make sure is
Dictionary<string, object>
And not
Dictionary<string, string>
Otherwise the constructor will confuse it for
object HtmlAttribute
Not as pretty though... but it works for the most part.
Lastly, take in mind that if you include AngularJS after jQuery, then it will use jQuery for selectors.
To anyone still looking for a solution to this problem , there is a simple way to make it work.
var currForm = $("#myForm");
currForm.removeData("validator");
currForm.removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(currForm);
currForm.validate();
You could put this code in $viewContentLoaded or other places which are relevant in your code.
While I understand some of the views here which discourage MVC views being used as a templates for your Angular code. My reason being its not not a natural way of doing things in angular and hence there are chances that you will run into issues like this one. But if you benefit from using MVC views as templates its not a path to hell. IT works and can benefit you as well. I have 2 use cases in my project where using MVC views make a lot of sense.
My project actually has a requirement where a client can turn of the required validation on certain field , for this I use the MVC custom data annotation validator which allows me to add or remove the data annotation at the time of rendering the view using a single class , if you were to build the same flexibility in angular , you would have to write a lot more code. So MVC views work great here for me as Custom Data Annotations are triggerd by the DisplayFor and EditorFor helpers
We are heavily invested in Internationalization and while angular is great at other stuff internationalization is not its strong suite ( at the time of writing this atleast )I still feel the internationalization support in MVC with .RESX works great and has been here long . This again uses the data annotation power of the DisplayAttribute.
TLDR : MVC views as templates may give you a few unexpected problems but are worth it if you are really using the full power of the data annotation pipeline created by Microsoft.
Hopefully someone comes up with a Angular HTML Helpers library in the future this would be much simpler.
Maybe using Angular for validation can be less painful than you think. Using a couple of custom directives, you could easily get something quite close to Razor with markup as simple as:
<validated-input name=username display="User Name" ng-model=model.username required</validated-input>
Check out my sample here and its inspiration here. It only implements required and number at the moment, but customizing it should be easy.
You can use ngval library. It brings data annotations to client side as angularjs validation directives.
I'm using a editor template for a object called Address.
#Html.EditorFor(model => model.Address)
In the template I have a few text boxes for the information about the user address.
this is how the text boxes are written in template
<p class="clear">
<label for="zip">
<span>#Html.LabelFor(x => x.ZipCode)</span>
#Html.TextBoxFor(m => m.ZipCode, new { #class = "big zip" })
</label>
</p>
but when it's rendered they broke my CSS putting
<div class="editor-label"> AND <div class="editor-field">
in the place of my paragraph tags.
There's any way I could change that?
I don't think your editor template is actually being used. Those are the default template values. You will have to provide some more information about your template in order to help. Where is it located? What is it called? etc.. (update your question, don't add this information as a comment)
What you would normally do is have a file called Address.cshtml and place this in a folder called EditorTemplates, either in the same folder as the view you are referencing, or in the Shared views folder if you need to share this template across various folders.
You should also add an #model Addresss (or whatever the fully qualified namespace is).
BTW, you are two labels being generated. That's not semantically correct.
Although not with Razor syntax, this article from Brad Wilson explains display/editor templates pretty well
What I mean by that is a type element that will have a label based on a value in my viewModel and also be able to submit that value back up to the viewModel so it can grab new results based on Current Page and Page Size. This is for creating a gridview in MVC that supports pagination.
None of the examples I've seen of MVC so far have had anything resembling a gridview. It's important that I create my own paging and not use any built in paging mechanisms or third party controls or html helpers or the like
I'd go with ActionLink. To build Urls you can either use Url.Action or Html.BuildUrlFromExpression(c => c.conTrollerAction)
If you use T4MVC, you will get some nice helpers that do exactly what you are looking for.
Something along the lines of:
<a href="<%: Url.Action(MVC.MyController.MyAction(Model.ActionMethodParam1, Model.ActionMethodParam2)) %>">
You can also use the Html.ActionLink helper:
<%: Html.ActionLink("Link Name", MVC.MyController.MyAction(Model.ActionMethodParam1, Model.ActionMethodParam2)) %>
T4MVC is a great little library that I use in every MVC app.