In my program I am trying to add extra controls dynamically on button click.Is it possible by using EditorTemplates?
This is my EditorTemplates
#model chPayroll.Models.HREducation.HRInfo
#{
var list = (IEnumerable<SelectListItem>)TempData["PassedDivision"];
var list1 = (IEnumerable<SelectListItem>)TempData["Country"];
}
#Html.HiddenFor(x => x.StaffId)
<tr>
<td>#Html.DropDownListFor(x => x.Country, list1, "-select-")</td>
<td>#Html.TextBoxFor(x=>x.Board)</td>
<td>#Html.TextBoxFor(x=>x.Level)</td>
<td>#Html.TextBoxFor(x=>x.PassedYr)</td>
<td>#Html.DropDownListFor(x=>x.PassedDivision,list,"-selected-")</td>
<td><input type="file" name="file"></td>
</tr>
Now I want to add all controls dynamically on button click.
I am calling listeditor from the view.
#model chPayroll.Models.HREducation.HRInfo
<div align="left">
<fieldset style="left:0px">
#using (Html.BeginForm("Addcontrols", "HREduInformation", FormMethod.Post))
{
<table >
<tr>
<th >Country</th>
<th>Board</th>
<th>Level</th>
<th>Passed Year</th>
<th>Division</th>
<th>certificate</th>
</tr>
#Html.EditorFor(m => m.listInfoeditor)
</table>
<input type="submit" value="Add New" id="savechanges" />
}
</fieldset>
</div
You can use Ajax to grab the rendered control Html.
Editing a variable length list
You can also go one step further and avoid the ajax call by using an already rendered template on the client side
Related
I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}
I've input:
<g:form role="search" class="navbar-form-custom" method="post"
controller="simple" action="addEntry">
<div class="form-group">
<input type="text" placeholder="Put your data HERE"
class="form-control" name="InputData" id="top-search">
</div>
</g:form>
And table:
<table class="table table-striped table-bordered table-hover " id="editable">
<thead>
<tr>
<th>Name</th>
<th>Created</th>
</tr>
</thead>
<tbody>
<g:render template="/shared/entry" var="entry"
collection="${entries}" />
</tbody>
</table>
Controller:
#Secured(['ROLE_USER', 'ROLE_ADMIN'])
class SimpleController {
def springSecurityService
def user
def index() {
user = springSecurityService.principal.username
def entries = Entry.findAllByCreatedBy(user)
[entries: entries]
}
def addEntry(){
def entries = Entry.findAllByCreatedBy(user)
render(entries: entries)
}
}
I just want to dynamically update the table with data from input string.
What is the best way?
Will be grateful for examples/solutions
You can update the table using AJAX with Grail's formRemote tag.
Input form
<g:formRemote
name="entryForm"
url="[controller: 'entry', action: 'add']"
update="entry">
<input type="text" name="name" placeholder="Your name" />
<input type="submit" value="Add" />
</g:formRemote>
HTML table
<table>
<thead>
<tr>
<th>Name</th>
<th>Created</th>
</tr>
</thead>
<tbody id="entry">
<g:render
template="/entry/entry"
var="entry"
collection="${entries}" />
</tbody>
</table>
Entry template
<tr>
<td>${entry.name}</td>
<td>${entry.dateCreated}</td>
</tr>
Controller
import org.springframework.transaction.annotation.Transactional
class EntryController {
def index() {
[entries: Entry.list(readOnly: true)]
}
#Transactional
def add(String name) {
def entry = new Entry(name: name).save()
render(template: '/entry/entry', collection: Entry.list(), var: 'entry')
}
}
How it works
When the add button is pressed the add controller method is called. The controller method creates the domain instance and renders the _entry.gsp template. But instead of refreshing the browser page, the template is rendered to an AJAX response. On the client side, the rendered template is inserted into the DOM inside of the tbody element with id entry, as defined in the formRemote tag by the update attribute.
Note that with this approach all of the entries are re-rendered, not just the new one. Rendering only the new one is a bit trickier.
Resources
Complete source code for my answer
Grails AJAX
Just to give you direction ( you are not showing any of your controller and js code.):
Create an action your controller ( the responsible controller) that will render the template /shared/entry by passing entries collection.
On submit of the form make ajax call to the action defined above, then replace the tbody html by the returned view fragment(template).
i am new in mvc and trying to learn.i want to display a form when ViewBag.Success is null or empty but if ViewBag.Success is true then i want to render a partial view.
here is my code
<div id="mydiv">
#if (ViewBag.Success != null && ViewBag.Success == true) //Show the message
{
Html.RenderPartial("Message");
}
else
{
#using (Html.BeginForm("Save", "Game", FormMethod.Post, new { #Id = "Form1" }))
{
<table border="0">
<tr>
<td>
Name :
</td>
<td>
<input name="name" type="text" />
</td>
</tr>
<tr>
<td>
Salary :
</td>
<td>
<input name="salary" type="text" />
</td>
</tr>
<tr>
<td colspan="2">
<input name="btnSubmit" type="submit" value="Save" />
</td>
</tr>
</table>
}
}
</div>
the error message i am getting when i am running like
Expected a "{" but found a "/". Block statements must be enclosed in "{" and "}". You cannot use single-statement control-flow statements in CSHTML pages. For example, the following is not allowed:
what i am doing wrong not being able to understand. please help & guide. thanks
# symbol is only required when your code is contained within an HTML element. The using statement does not need the # because it is a direct decedent of your if else block.
Example:
<div> <!-- html tag -->
#if(something == somethingElse) // requires # because direct decedent of html tag <div>
{
<p>
#for (var i=0; i < len; i++) // requires # because direct decedent of html tag <p>
{
if(i == 1) // doesnt require #, not decedent of any HTML tag, instead direct decedent of another razor statement (for)
{
//do something
}
}
</p>
}
</div>
The # sign is use to distinguish between a simple string / HTML and razor statements. You only need that when you are writing C# code between HTML code. But when you are have started a C# code block, the ASP.NET MVC View Engine is intelligent enough to understand that the code that follows is C# and not simply some string.
I am trying to use a partial view to represent rows of a table in my project. I currently have
<table>
<thead>
<tr>
<th >
Column 1
</th>
<th >
Column 2
</th>
<th >
Column 3
</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model.Items)
{
#Html.Action("ItemCalculatedView", new { Id = item.Id})
}
</tbody>
</table>
In my partial view I have this
#using (Ajax.BeginForm("SaveStuff", "Whatever",
new { id = #Model.Id }, new AjaxOptions()
{
HttpMethod = "Post",
OnSuccess = "Success"
}))
{
#Html.HiddenFor(m => m.Id)
<tr>
<td>
#Html.Label("Col1", Model.Col1)
</td>
<td>
#Html.TextBox("Number", Model.Number)
</td>
<td>
<input type="submit" id='submit-#Model.Id'/>
</td>
</tr>
}
How can I make this work?
You can put a form inside a table cell, but you can't have the form inside a tbody element, or spanning multiple columns. So there are three options:
Use a CSS layout instead of a table, or use divs with CSS display set to "table". (for example)
Put the entire form (TextBox and Submit) inside a td
Put another table inside the td element
I'd recommend #1 -- use a CSS layout to construct the table, since it's difficult to style table tags:
Main
<div class="table">
<div class="header-row">
<div class="header-cell">Column 1</th>
<div class="header-cell">Column 2</th>
<div class="header-cell">Column 3</th>
</div>
#foreach(var item in Model.Items)
{
#Html.Action("ItemCalculatedView", new { Id = item.Id})
}
</div>
Partial
#using (Ajax.BeginForm(
actionName: "SaveStuff",
controllerName: "Whatever",
routeValues: new { id = #Model.Id },
ajaxOptions: new AjaxOptions
{
HttpMethod = "Post",
OnSuccess = "Success"
},
htmlAttributes: new { #class = "row" }
))
{
<div class="cell">
#Html.HiddenFor(m => m.Id)
</div>
<div class="cell">
#Html.Label("Col1", Model.Col1)
</div>
<div class="cell">
#Html.TextBox("Number", Model.Number)
</div>
<div class="cell">
<input type="submit" id='submit-#Model.Id'/>
</div>
}
CSS
.table { display: table; }
.header-row, row { display: table-row; }
.header-cell, cell { display: table-cell; }
You have several issues here. First, as dbaseman mentions, you can't place forms within the structure of a table and have it be legal HTML. It may work, or it might not, and even if it does work, you can't guarantee it will continue to work.
I would instead wrap your table in the form, and then on the post figure out which button was pressed based on its value and/or index.
I would strongly advise against using css tables for tabular data. It's just not semantically correct.
Another possible solution is, instead of using the Ajax.BeginForm, instead use jQuery $.ajax and then you can select a row of data in javascript to post to the server.
I have an Entity (QuoteSheet) that contains a child entity (QuoteTask), which is loaded using the EntityFramework. However, I am receiving an error when I submit this form.
I have created an edit page for the QuoteSheet entity, which then uses an EditorTemplate to edit the QuoteTask child entity.
The controller code is as follows:
public ActionResult TestEdit(int Id)
{
var quote = DataContext.QuoteSheets.Where(x => x.ID == Id).FirstOrDefault();
return View(quote);
}
[HttpPost]
public ActionResult TestEdit(Models.QuoteSheet quote)
{
return View(quote);
}
A stripped down version of the view is as follows:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.HiddenFor(x => x.JobID);
<div class="sectionHeader">Sheet Details</div>
<div class="sectionContent">
<table>
<tr>
<td width="150">Sheet Desc.</td><td>#Html.TextBoxFor(x => x.Description, new { size = "50" })</td>
</tr>
<tr>
<td>Quantity Required</td><td>#Html.EditorFor(x => x.Quantity)</td>
</tr>
</table>
</div>
<div class="sectionHeader">Tasks</div>
<div class="sectionContent">
<table id="Tasks">
<tr>
<th>Labour Group</th>
<th>Task Description</th>
<th>Total Hrs</th>
<th>Rate</th>
<th>Cost</th>
</tr>
#Html.EditorFor(x => x.QuoteTasks)
</table>
<input type="button" name="AddTasks" id="AddTasks" value="Add" />
</div>
<input type="submit" value="Submit" />
#Html.ValidationSummary()
}
And the EditorTemplate is:
#model Ornavi.Models.QuoteTask
<tr>
<td>#Html.EditorFor(x => Model.LabourGroup)</td>
<td>#Html.EditorFor(x => Model.Description)</td>
<td>#Html.EditorFor(x => Model.TotalHours)</td>
<td>#Html.EditorFor(x => Model.Rate)</td>
<td>#Html.HiddenFor(x => Model.ID)</td>
</tr>
When I submit the form, I am getting the following error:
The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph.
This only occurs when I use the EditorTemplate - if I remove the editor template and just submit the main entity, it works fine.
I have placed a breakpoint in the [httppost] TestEdit function, but the exception occurs before it reaches this point.
Any ideas on how to successfully use an EditorTemplate to edit a child entity?
The problem is, that the default modelbinder tries to instantiate your EF class and set the navigation properties when binding the form data to your parameter types.
See some similar questions like this one.
You have two options:
Don't use your EF classes as viewmodels but create own viewmodel classes to pass the data between controller and view.
Don't bind directly to the EF class in your Edit controller action but use a FormCollection parameter and bind yourself with UpdateModel as shown in the linked question.