First, declare a variable for the html string of your form:
<script type="text/javascript"> var formHtml = ""; function canRender() { return _canRender; } $(function () { _canRender = false; }); </script>
We use canRender so we can defer the execution of javascript of the form's html string
<div id="editor" style="visibility: hidden"> @using (Html.BeginForm(null, null, FormMethod.Post, new { id = "theForm" })) { <fieldset> <legend>Person</legend> @Html.HiddenFor(x => x.PersonId) @Html.HiddenFor(x => x.RowVersion) <div class="editor-label"> @Html.LabelFor(x => x.Username) </div> <div class="editor-field"> @Html.EditorFor(x => x.Username) @Html.ValidationMessageFor(x => x.Username) </div> <div class="editor-label"> @Html.LabelFor(x => x.Firstname) </div> <div class="editor-field"> @Html.EditorFor(x => x.Firstname) @Html.ValidationMessageFor(x => x.Firstname) </div> <div class="editor-label"> @Html.LabelFor(x => x.Lastname) </div> <div class="editor-field"> @Html.EditorFor(x => x.Lastname) @Html.ValidationMessageFor(x => x.Lastname) </div> <div class="editor-label"> @Html.LabelFor(x => x.Country.CountryId) </div> <div class="editor-field"> <table style="border-style: none"> <tr> <td style="border-style: none"> @Html.AjaxComboBoxFor(x => x.Country.CountryId, "/Countries/Management/Lookup/", "/Countries/Management/Caption/", new { }, new { sub_info = true, can_render_callback = "canRender", textbox_width = 200 }) </td> <td style="border-style: none"> @Html.ValidationMessageFor(x => x.Country.CountryId) </td> </tr> </table> </div> <div class="editor-label"> @Html.LabelFor(x => x.FavoriteNumber) </div> <div class="editor-field"> @Html.EditorFor(x => x.FavoriteNumber) @Html.ValidationMessageFor(x => x.FavoriteNumber) </div> <p> <input type="submit" value="Save" /> <input type="button" id="Closer" value="Close" /> </p> </fieldset> <div style="max-width: 500px; width: 500px;"> @Html.JsAccessibleValidationSummary(excludePropertyErrors: true) </div> } <script type="text/javascript"> $(function () { if (!canRender()) return; var scope = $('#theForm'); parseDynamicContent(scope); $('#Closer', scope).click(function (e) { closeForm($(scope)); }); $('input[type=submit]', scope).click(function (e) { try { e.preventDefault(); if (!scope.valid()) { // alert('has invalid'); return; } save(scope); // closeForm(scope); } catch (e) { alert("Error " + e); } }); $(scope).attr('id', guid()); }); function save(scope) { $.ajax({ url: '/People/Management/SaveViaAjax', type: 'POST', data: $(scope).serialize(), success: function (result) { var isOk = $(scope).modelValidation(result); if (isOk) { var isNew = $('#PersonId', scope).val() == ''; if (isNew) { $('#PersonId', scope).val(result.PersonId); } $('#RowVersion', scope).val(result.RowVersion); if (isNew) { $(scope).closest('table').flexReload(); } else { setFgEditText(scope, 'Username', $('#Username', scope).val()); setFgEditText(scope, 'Firstname', $('#Firstname', scope).val()); setFgEditText(scope, 'Lastname', $('#Lastname', scope).val()); setFgEditText(scope, 'FavoriteNumber', $('#FavoriteNumber', scope).val()); setFgEditText(scope, 'Country', $('#Country_CountryId', scope).ajc().getText()); closeForm(scope); } } // $('#firstTable').flexReload(); }, error: function (a, b, c) { alert(a.statusText); alert(b); alert(c); } }); //ajax }//save </script> </div>
Here's the flexigrid setup and getting the form's html string:
<script type="text/javascript"> $(function () { // main.. setupForm(); setupFirstTable(); // ..main }); function setupForm() { formHtml = $('#editor').html(); $('#editor').remove(); } function setupFirstTable() { $('#firstTable').flexigrid({ url: '/People/Management/List', dataType: 'json', colModel: [ { display: 'User', name: 'Username', width: 150, sortable: true, align: 'left' }, { display: 'Firstname', name: 'Firstname', width: 150, sortable: true, align: 'left' }, { display: 'Lastname', name: 'Lastname', width: 150, sortable: true, align: 'left' }, { display: 'Favorite#', name: 'FavoriteNumber', width: 150, sortable: true, align: 'left' }, { display: 'Country', name: 'Country', width: 150, sortable: true, align: 'left' }, { display: 'RowVersion', name: 'RowVersion', width: 150, sortable: true, align: 'left', hide: true } ], buttons: [ { name: 'Add', bclass: 'add', onpress: add }, { separator: true }, { name: 'Edit', bclass: 'edit', onpress: edit }, { separator: true }, { name: 'Delete', bclass: 'delete', onpress: del } ], singleSelect: true, sortname: 'Lastname', sortorder: 'asc', usepager: true, title: 'Persons', useRp: true, rp: 5, rpOptions: [5, 10, 15, 20, 25, 40], showTableToggleBtn: true, width: 900, height: 'auto', preProcess: function (data) { var rp = getFgRowsPerPage($('#firstTable')); for (i = data.rows.length; i < rp; ++i) { data.rows.push({ 'id': '', 'cell': ['', '', '', '', '', ''] }); } return data; } }); // flexigrid setupGrid($('#firstTable')); } //setupFirstTable function add(com, grid) { try { closeFormByGrid(grid); showAddFormByGrid(grid, formHtml); } catch (e) { alert('error ' + e); } } function edit(com, grid) { closeFormByGrid(grid); var items = $('.trSelected', grid); var item = items[0]; var pk = item.id.substr(3); if (pk.length == 0) return; $.ajax({ url: '/People/Management/GetUpdated/' + pk, type: 'POST', success: function (data) { showEditForm(item, formHtml, function () { var form = $('form', grid); $('#PersonId', form).val(data.Record.PersonId); $('#Username', form).val(data.Record.Username); $('#Firstname', form).val(data.Record.Firstname); $('#Lastname', form).val(data.Record.Lastname); $('input[id=Country_CountryId]', form).val(data.Record.CountryId); $('#FavoriteNumber', form).val(data.Record.FavoriteNumber); $('#RowVersion', form).val(data.Record.RowVersion); $('#Country_CountryId', form).ajc().showCaption(); setFgEditText(grid, 'Username', data.Record.Username); setFgEditText(grid, 'Firstname', data.Record.Firstname); setFgEditText(grid, 'Lastname', data.Record.Lastname); setFgEditText(grid, 'FavoriteNumber', data.Record.FavoriteNumber); }); //showEditForm } //success }); //ajax }//edit function del(com, grid) { var deleteIt = confirm('Do you want to delete the selected record?'); if (!deleteIt) return; var pk = getCurrentRowPk(grid); var version = getFgGridColumnText(grid, 'RowVersion'); // alert(pk + " " + version + " " + encodeURIComponent(version)); $.ajax({ url: '/People/Management/Delete', type: 'POST', data: 'pk=' + pk + '&version=' + encodeURIComponent(version), success: function (result) { if (result.IsOk) { $('#firstTable').flexReload(); } } }); } </script>
Lastly we put this at the end of the html:
<script> $(function () { _canRender = true; }); </script>
Here's the Flexigrid form-inliner helper functions:
function showEditForm(selectedTr, html, assignerFunc) { $(selectedTr).after('<tr class="fgEdit" editId=' + selectedTr.id + '><td width="1" colspan="20" style="border-width: thin; border-top: thick; border-color: #EEE; white-space: normal;"><span></span></td></tr>'); var content = $('td > span', $(selectedTr).next()); // var form = $(content).hide().html(html); var form = $(content).html(html); assignerFunc(); $(content).show(); } function showAddFormByGrid(grid, formHtml) { var tbl = $('.bDiv table', grid); showAddForm(tbl, formHtml); } function showAddForm(tbl, formHtml) { var tbody = $('tbody', tbl); if (tbody.length == 0) { $(tbl).append($('<tbody/>')); tbody = $('tbody', tbl); } $(tbody).prepend('<tr class="fgEdit"><td width="1" colspan="20" style="border-width: thin; border-top: thick; border-color: #EEE; white-space: normal"><span></span></td></tr>'); var content = $('tr td span', tbody); $(content).html(formHtml); }
Flexigrid CRUD(inline form) example with ASP.NET MVC, complete with model validation:
http://code.google.com/p/flexigrid-crud-example/downloads/list
Known issues:
1. Not with flexigrid per se; but when inside of flexigrid, the jQuery Ajax ComboBox's result area is far from its textbox when using Firefox or IE, have made a work-around in Chrome though. If you could lend a help in correcting that problem of jQuery Ajax ComboBox, I'll be more than glad to accept a patch.
2. If the flexigrid has no rows, the inline form is not in full width. Accepting patch for flexigrid code or helper code.
Sample output |
jQuery Ajax ComboBox's detached result screenshot(IE and Firefox problem) |
Thanks, but this line @Html.JsAccessibleValidationSummary(excludePropertyErrors: true) doesn't seem to be working for me.
ReplyDeleteI am using ASP.NET MVC4
Also, I am looking for a way to invoke the regular Create/Edit view from the grid as I need to first get information about current selected row (more columns). Do you know how to achieve this?
In order to use JsAccessibleValidationSummary , you got to add JsValid's reference in Web.config. Line #30 http://code.google.com/p/flexigrid-crud-example/source/browse/trunk/FlexigridCrudDemo/FlexigridCrudDemo/Web.config#30
DeleteThe source code for JsAccessibleValidationSummary: http://www.ienablemuch.com/2011/07/ivalidatableobject-client-side.html
I've added JsValid reference (in the bin folder of my application). I also added the following into my web.config
DeleteHowever, if I include the code referencing JsAccessibleValidatonSummary, I still get an error. What else is missing?
When I try to get your application running I am getting
ReplyDeleteCannot open database "TestCrud" requested by the login. The login failed.
Login failed for user 'user name here'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.SqlClient.SqlException: Cannot open database "TestCrud" requested by the login. The login failed.
Login failed for user 'user name here'.
Source Error:
Line 47:
Line 48:
Line 49: _sf = fc.BuildSessionFactory();
Line 50: return _sf;
Line 51: }
I am unable to run the sample, I am getting this error: I also see that the error refers to the places I don't have in my configuration.
ReplyDeleteI haven't used NHibernate before, is it possible for you to create a simpler sample (beginners style) with minimum extra dependencies?
FluentNHibernate.Cfg.FluentConfigurationException was unhandled by user code
HResult=-2146233088
Message=An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
Source=FluentNHibernate
StackTrace:
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory() in d:\Builds\FluentNH\src\FluentNHibernate\Cfg\FluentConfiguration.cs:line 235
at FlexigridCrudDemo.Mappers.ModelsMapper.GetSessionFactory() in c:\Flexigrid\FlexigridCrudDemo\FlexigridCrudDemo\Mappers\NhDbContext.cs:line 49
at FlexigridCrudDemo.NinjectControllerFactory.b__3(IContext x) in c:\Flexigrid\FlexigridCrudDemo\FlexigridCrudDemo\NinjectDependencyResolver.cs:line 61
at Ninject.Activation.Providers.CallbackProvider`1.CreateInstance(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Providers\CallbackProvider.cs:line 45
at Ninject.Activation.Provider`1.Create(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Provider.cs:line 39
at Ninject.Activation.Context.Resolve() in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\Activation\Context.cs:line 157
at Ninject.KernelBase.b__7(IContext context) in c:\Projects\Ninject\Maintenance2.2\ninject\src\Ninject\KernelBase.cs:line 375