I have two collections that more or less look like this:
[BindProperty]
public List<MyObject> MyObjects { get; set; } = new List<MyObject>();
[BindProperty]
public List<MyOtherObject> MyOtherObjects { get; set; } = new List<MyOtherObject>();
So they're bounding to the server, but I'm not quite sure how to bind them to the client. Or I'm just doing it wrong. The lists are adding to an HTML table when the page loads, but there's no direct binding:
#foreach (var item in Model.MyObjects)
{
<tr>
<td>
Title
</td>
<td>
#Html.DisplayFor(m => item.Property)
</td>
</tr>
}
The issue is that I need to POST to the server to add items to each list at different points. And when I do that, I just return Page();. I'm not redirecting because at this point, nothing is being saved to the database and the form isn't complete.
From my current knowledge, I figure I have two options: redirect and pass the data in the query string or save the data to a cookie and repopulate on every POST.
Both aren't great options. Is there a better way to do this?
Model Binding is designed to work with form values. If you aren't repopulating your collections from persisted data on the server, you need to add form fields for each item to get Model Binding to work. If you are creating a multi-step, wizard-like form, you usually persist unsaved values from each step in hidden fields from one step to the next.
Related
I have two buttons on my HTML page inside a form using the "POST" method. On click of first button, a function in the model called "OnPostSubmitBtn()" would fire up, calling another class a doing a bunch of calculations to an input that I have received in a textbox in the same form, this would then put it in an outputbox in the same form. The second button, is to clear both boxes. When it is clicked, a function in the model called "OnPostClearBtn()" would fire up, clearing both boxes.
On the same HTML page but below this form, I am displaying the below information. This information is filled by the OnGet() method in the model. Inside this "OnGEt()" method, I am establishing a connection to a database, getting the information back and adding it to a list.
The problem is that every time I click on Submit or clear, the contents below are gone (Contents filled from the database into the tables below). It seems like the OnGet method is only executed once and every time I click on a button, a new instance is made, but the OnGet method is not firing, rightfully..
public class Comments
{
public string name { get; set; }
public string email { get; set; } = "NULL"; // default null
public string comment { get; set; } = "No Comment";
public string createdAt { get; set; }
}
<h2>Comments</h2>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Comment</th>
<th>Time of creation: </th>
</tr>
</thead>
<tbody>
#foreach(var item in Model.comments){
<tr>
<td>#item.name</td>
<td>#item.comment</td>
<td>#item.createdAt </td>
</tr>
}
</tbody>
</table>
There are two ways to solve the problem but I am sure they are just a walk around and not real solutions someone would using int he professional world. You can call the OnGet() method again in both OnSubmit buttons, or I can move my database connection and populating the list from the OnGet to the Model's constructor, because it will be called every time.
I am sure there are professional ways to do it, or is doing it the way I did it sufficient enough? What would be the equivalent function that would be called every time regardless of whether its a new instance or not?
If you want the same data available in both the OnGet and OnPost methods, the workaround you have identified is the correct one - call the database in both handlers. Usually, you would write one private method in your PageModel class that does this then call that method in the relevant handler.
I would avoid putting this in the constructor because it is not usual to need exactly the same data for both get and post methods. Often, you only need data in a post method if model validation fails and you need to redisplay the form. Also, you might add other handler methods at some point in the future that don't need it at all.
In the controller, I do a ViewBag, which I later transmit to the view, fill in the data there and want to send it in a post request, but the viewbag returns null how to return the selected data from the ViewBag
Sorry, but AFAIK this is not how the ViewBag variable was meant to be used. It is for sharing small amounts of data from the Controller to the view (on the client), not the other way around.
To get data back to the server you'll need to explicitly post back the data you need in a request to your server from your client view.
Lets break this down
#foreach (var item in ViewBag.List)
{
<option value="#item.Id">#item.Name</option>
}
In the above code, ViewBag should exist as a dynamic variable, and if you set List in the view bag object when the view is being requested by the client it will contain whatever data you put there.
<button class="btn" type="submit" name="action">
Submit
</button>
Here, in the html above, you are now trying to Post back whatever options you select. it is here youll need to specify an endpoint that will recieve the form data and do whatever is required with it
I would take bigger amount of data from MODEL
MODEL
public string Name{ get; set; }
VIEW
#model IEnumerable<*YourProjectName*.Models.*ModelName*>
Code above, between * * change it to right project name and Model name.
It should do it automatically after you write #model
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
</tr>
}
Is it possible to loop through list of models and update displayed data in view without refreshing the page or making ajax call to server?
Scenario:
Model:
public SomeModel
{
public int Id { get; set; }
public string LinkName { get; set; }
public string ItemDecsiption { get; set; }
public string Text { get; set; }
}
List of SomeModel objects is inicialized, filled with data and passed to View in controller ActionResult. I can see all data in view (i am able to loop through individual models and create list from SomeModel.LinkName property.
<ul>
<% foreach (SomeNamespace.SomeModel m in Model)
{ %>
<li class="green"><%= m.LinkName %></li>
<% } %>
</ul>
What I want to do is to divide page content section into two parts-one with menu (consisting of links created from every LinkName in Model) and second containing block with description and text (for id currently clicked in menu). Now comes the trick part. I want to be able to change displayed data in second block after clicking Link in menu without refreshing the page or making ajax call to server (since all the data I need is already available to client side). Only solution I could think of is to generate hidden blocks for every SomeModel object and then write jquery to manipulate visibility after link click. What I want to know is if there is some more elegant way to accomplish this.
Project is written in C#.NET 3.5 ASP.NET MVC 2.0
The only way to do this would be to use JavaScript to manipulate the DOM.
Depending on the markup which you'll produce, hidden html blocks may be the most elegant solution of all. Like, for intance, if you switch visibility by simply changing a class of block which should be visible without changing the DOM.
The other option will be to prepare json object from Model and use it as data source for visible markup. But this may lead to raise of complexity which is not necessary in most of the cases.
there is another way.
1.var data=#Model.ToJson() in js; there is not a ToJson function ,that just what you need to do
2.only one content block
3.when click menu,find element in data,and set block content use js
I have a grid with the following object:
public PagedList<GridList> PagedList { get; set; }
public class GridList
{
public Employee EmployeeItem { get; set; }
public bool isChecked { get; set; }
}
My aspx implemented the table inside a loop and then I put a checkbox for each Employee:
<%foreach (var item in Model.PagedList )
{%>
<tr>
<td align="center">
<%: Html.CheckBox(item.EmployeeItem.ID.ToString(), item.isChecked)%>
</td>
</tr>
<% }%>
I need to keep all the checkboxes selected when the user change the page. So, if he selects 2 or 3 options of a page an then change the page number, when he come back to this page, the same checks should be marked.
I tried many solutions but I wont comment them here just to expect a better one. All the orders I tryed I had problems that I cannot solve.
When the user click to got to another page, the code goes to the [HttpGet] method.
Thanks for the help.
You will have to somehow send the checked values to the server when performing pagination or you will loose them. You have a couple of possibilities:
Put the checkboxes inside an HTML form alongside with the pager and make the pager links submit buttons of this form.
Use AJAX to perform the pagination and refresh only the grid portion of the DOM and do not touch at the checkboxes. This way they will preserve their values.
Subscribe to the onclick event of the pager links and inside cancel the default action (evt.preventDefault()), harvest the values of the checkboxes and append them to the query string of the url that will perform the pagination. Then redirect to this new url.
I have a Telerik MVC ComboBox which contains a list of locations. The client wants the end user to be able to directly enter new locations into the list.
Upon submitting the form, it should accept a new value and insert into the locations table, and of course update the LocationID of the record being added to the ID of the newly inserted location.
Read below for code snippets
I've read that the ComboBox does allow you to enter in values that are not in the list, and used the demo (Here)
Code to save location, edit locationID is not a problem. My problem here is that my Combo box contains a list of integer/string value pairs, not string/string. And thus, the issue I have in my code is that if I try and submit a new location name, it tries to validate it and says its not a number.
I need a way to try and suppress this validation, just for the LocationID field, but still protect against null values.
BEGIN EDITS
EDIT: I did find this post, but as the OP there says, the javascript hack is not very extensible, so I really want to avoid it.
EDIT:
I ended up using the javascript hack, its all I've found which works. I plan to encapsulate this in a method or attribute, and post it as an answer.
I found that with this hack, it did not work in Firefox or Chrome if I place the code block inside the document ready event using Telerik().ScriptRegistrar().OnDocumentReady(), the properly window.mvcClientValidationmetadata is somehow cleared when it reaches this event, even though the metadata are properly pushed in originally.
To get around this, I had to manually put the code in its own script block just under the form closing tag (which is where the client-side validation array is rendered).
END EDITS
Additionally, right now I'm binding to my model directly like so:
public JsonResult Create(MyEntity Model)
I'm not sure how that's going to work out when it comes time to do model binding, I'm guessing it may just return an error, and I won't even reach my action method code.
So I guess the idea here would be to use a FormCollection in the method signature, detect for a non-integer LocationID, insert update, and then run UpdateModel()? Of course, welcome to better suggestions.
Thanks!
Code Snippets
Model:
class IntegerValueList
{
public Int16 ID { get; set; }
public string Name { get; set; }
}
var lists = new Dictionary<string, IEnumerable<object>>();
lists["Locations"] = (from record in db.Locations
orderby record.Name
select new IntegerValueList
{
ID = record.LocationID,
Name = record.Name
}).ToList();
Controller:
LocationList = new SelectList(lists["Locations"], "ID", "Name", LocationID);
View:
<td>
<div class="editor-field">
<%: Html.Telerik().ComboBoxFor(model => model.LocationID)
.BindTo(Model.LocationList)
.Filterable(c => c.FilterMode(AutoCompleteFilterMode.Contains))
%>
<%: Html.ValidationMessageFor(model => model.LocationID, "*") %>
</div>
</td>
When I've had to do this in the past, I have used a textbox for the field with a label like "Enter Location", and then a dropdown below it with a label like "Or select...", and then use the onChange event of the dropdown to populate the textbox. Now you are not validating the dropdown.
You could even put a "Select" link next to the textbox and have the dropdown hidden until the link is clicked. The drawbback is that we could end up with San Diego, SanDiego and Sandiego all entered in the location list...but then your customer's requirement doesn't let us explicitly prevent that.