I have two Model classes like so:
Program:
public class Program
{
public int ProgramId { get; set; }
public string Name { get; set; }
public virtual Playlist chosenPlaylist { get; set; }
public virtual IList<Playlist> Playlists { get; set; }
}
public class Playlist
{
public int PlaylistId { get; set; }
public string Name { get; set; }
public int NumberVotes { get; set; }
public virtual IList<Song> Songs { get; set; }
}
In my Edit Program View, I want to update the chosenPlaylist so I can allow the user to select none or one of the Program's Playlists.
For example:
Program 1:
Playlist 1
Playlist 2
Chosen Playlist: Playlist 1
So the user can then edit and select None (so no playlist), 1 (won't change anything) or 2 and that gets saved to the database.
I've tried to create a dropdownlist in my Controller but it won't update.
Here's what I have in both my GET and POST Edit ActionResults:
ViewBag.chosenId = new SelectList(program.Playlists, "PlaylistId",
"Name", program.chosenPlaylist.PlaylistId);
And in my View:
#Html.DropDownList("PlaylistId", (SelectList)ViewBag.chosenId)
This displays the list fine and pre-selects the chosen Playlist, if there is one (if not, I'll write code for it to default to the first). If there aren't playlists in a Program, that's easy to control.
However, problems:
Doesn't update my model. If Playlist 2 is the chosen one, for example, and I choose P1, it continues to display P2 after the POST event.
I want to include an option in the dropdownlist for it not to pick any value (so, place a NULL in that field). Is that possible?
There are no errors thrown, everything seems to work except for the most important part - updating the database.
Make sure there are no #Html.HiddenFor or similar rendering the same item.
There's 2 things you can do:
Change #Html.DropDownList("PlaylistId", (SelectList)ViewBag.chosenId) into #Html.DropDownList("chosenPlaylist.PlaylistId", (SelectList)ViewBag.chosenId)
Or use the Html.DropDownListFor(m => m.chosenPlaylist.PlaylistId, (SelectList)ViewBag.chosenId)).
When using:
#Html.DropDownList("PlaylistId", (SelectList)ViewBag.chosenId)
you have to rename the PlaylistId select list to something that is not the same as the propertyname that stores the selected Id, else it wont be marked as selected.
(which makes sense now that im typing it, you cant store the selected value into something that has the same as the select list)
Basically saying:
#Html.DropDownList("MySelectListId", (SelectList)ViewBag.chosenId)
will work.
You can look at the comments on this issue at codeplex for more information: http://aspnet.codeplex.com/workitem/4932
Related
I am new to .net core - have been using aspx web pages and .net framework 4.x for a number of years. I have a project where we want to display different controls (textbox, dropdown, checkbox) on the page based on values returned from a query. For example, user chooses "A" from a dropdown list and it shows 10 controls, if they choose object B it shows 8 controls, etc. Previously in .net framework, I would use a content placeholder with an ID and then find that ID and start adding controls (controls.Add(newControl)) in the placeholder. It doesn't seem that is an option with .net core. It seems like this would be a common need for various web applications, but I'm not finding many hits.
Another question is whether this can be done in the code behind or if it has to be done on the client-side. If one of the controls in the list is a dropdown, there will be a query that a subroutine will run to get the Key/Value pairs for the dropdown. To me this means it would be more effective on the server side.
I haven't really found any good examples when I do some searching. Can anyone point me to a good resource or provide me with a basic example - either client-side or server-side? Thanks!
There are many options, but I'll describe a simple one, using server side processing. As you explained in your comment, there will be 2 pages:
One that will display the select element that will be used to choose a set of controls.
The page that will be returned according to the previous choise, displaying the selected set of controls.
I assume that you know how to build the first page.
For the second page, you can leverage the ASP.NET Core MVC pattern to achieve the desired result.
You will need the three usual MVC elements:
An Action in a Controler.
A ViewModel for your Razor View.
A Razor View.
The Action does the following:
Receives the id of the selected set of control (via the Action's parameter).
Uses this id to retrieve the information about the corresponding set of controls from your repository.
Builds a ViewModel out of the received information.
Builds a View using the obtained ViewModel.
Return the builded View.
Here is some simplified example code:
In your controller, add the following method:
#!lang-cs
Public IActionResult GetProgramControlSet(int ProgramId)
{
// Here, use the id to get the data from your repository
// that will be used to build set of controls.
// Supposing you have defined a GetControls method,
// it could look like:
var SelectedControls = MyRepository.GetControls(ProgramId);
// If needed, you can build a ViewModel out of the received SelectedControls.
var SelectedControlsViewModel = new ControlSetViewModel(SelectedControls);
return View(SelectedControlsViewModel)
}
Of course, many things are missing here: error handling, etc...
Here is what the ViewModel could be:
#!lang-cs
public class ControlSetViewModel
{
public string Name { get; private set; }
public List<IControl> Controls { get; private set; }
public ControlSetViewModel(...)
{
// Whatever needs to be done to construct the ViewModel
}
}
public enum ControlKind
{
Button,
Select,
Textarea
//...
}
public interface IControl
{
ControlKind Kind { get; }
}
public class ControlButton : IControl
{
public ControlKind Kind => ControlKind.Button;
public string Label { get; set; }
public string Text { get; set; }
public string Color { get; set; }
// ... All other needed properties for the button
}
public class ControlTextarea : IControl
{
public ControlKind Kind => ControlKind.Textarea;
public string Label { get; set; }
public string PlaceholderText { get; set; }
public string RowCount { get; set; }
// ... All other needed properties for the textarea
}
public class ControlSelect : IControl
{
public ControlKind Kind => ControlKind.Select;
public string Label { get; set; }
public string PlaceholderText { get; set; }
public List<SelectOption> Options { get; set; }
// ... All other needed properties for the select
}
public class SelectOption
{
public string Text { get; set; }
public string Value { get; set; }
}
You could also use inheritance instead of interface for the control classes.
Now the view.
It is a Razor page containing something akin to
#model ControlSetViewModel
#*... some HTML ...*#
<div>
<h1>#Model.Name</h1>
#foreach(var control in Model.Controls)
{
<div>
switch(control.GetControlKind())
{
case ControlKind.TextArea:
var Textarea = (ControlTextarea)control;
<label>#Textarea.Label</label>
<textarea rows="#Textarea.RowCount"/>
break;
case ControlKind.Select:
var Select = (ControlSelect)control;
<label>#Select.Label</label>
<select>
#foreach(var option in Select.Options)
{
<option value="#option.Value">#option.Text</option>
}
</select>
break;
#*... etc ...*#
default:
#*... etc ...*#
}
</div>
}
</div>
#*... More HTML ...*#
Of course this is far to be finished. All the infrastructure and code that will actually react to the displayed controls is missing.
Is it a form you that will be posted?
Is it Javascript code that will react to the control manipulation?
Or another mecanism?
This questions will need to be addressed.
I'm not sure how to phrase this question correctly but here's an issue I am currently facing in a backend development project.
Suppose I have a table called Users. I create a model called User:
public partial class User
{
public int Id { get; set; }
public string Name { get; set; }
public id JobTitleId { get; set; }
... other fields
}
A user has a Job title which is related to a JobTitles table. The way its structured now is the FE will call an api, lets call it dictionary api which returns a list of objects with the job titles. So, something like this:
[{id: 1, title: 'aa'}, {id: 2, title: 'bb'} ...]
So, based on the jobtitleid that was available, this api will be called and the view will show the title based on the id.
Now, I feel like this is not really efficient since if we have a hundred or thousand job titles, FE will have to parse through each object to match the id.
Is there a better way to display the name of the job title given the ID? I cannot return the job title directly because if the user's job title is not updated but that particular form with the job titles is sent with a PUT request, it will return the name of the job title instead of the ID back to the users table.
Also, the job title will be an autocomplete field on the Frontend which will call an api on the backend when a user inputs the name of the job title, thereby returning the id of that job title back to the Backend when a user is updated with a new job title.
Sorry if Im not clear enough, I can ive more details if required.
have you tried doing something like this?
I am assuming JobTitleId belongs to JobTitles class
public partial class User
{
public int Id { get; set; }
public string Name { get; set; }
public id JobTitleId { get; set; }
[ForeignKey("JobTitleId")]
public JobTitles JobTitles{ get; set; }
}
so as you know classes are object by reference and when you pass the User class to your view, the moment you change the user title from the dropdown it will also change the jobtitleId accordingly
We have c# model class with following fields:
public class BasicDetailsModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Mobile { get; set; }
}
Once user clicks on save button with (Name="x", Email="x#gmail.com", Mobile=989), these details get saved in database. Now, in case user updates any of these fields i.e. Name to "y", we have to send Email,Mobile too although these have not changed.
I have oversimplified the problem here. We have multiple cases where Models have over 20 fields and we are updating more than 5 models through single save click.
How can we update only what's needed and assure everything else already saved remain as it is i.e. in this case client would only send (Name="y") and Database will have (Name="y", Email="x#gmail.com", Mobile=989).
I don't want to make multiple database calls before saving and want flexibility that user remove value from already entered fields i.e. can change Name from "y" to null.
I have an ASP.Net MVC 5 (C#) application and I'm giving my users the ability to like posts and comments.
for this I have a Model called Likes with the following Properties:
public class Like
{
public Like()
{
this.CreatedUTC = System.DateTime.UtcNow;
this.isActive = true;
}
public long id { get; set; }
public string UserID { get; set; }
public bool isActive { get; set; }
public LikeType Type { get; set; }
public DateTime CreatedUTC { get; set; }
}
Type is an enum and it can be either Comments or Posts. I've also added the following Navigation Property to both Post Model and Comment Model:
public virtual ICollection<Like> Likes { get; set; }
My question is, can I have a setter function in the above line of code where it would automatically set Comments and Posts for the Like type? I know I can use the Value variable in the Setter but using Google I couldn't find how to use it for complex types as I have above (Like).
I'm sure this would be a better way of doing this than in the repository manually set that enum every-time I'm going to save a like.
UPDATE:
Seeing how we're starting a nice little conversation about this Questions, I will throw another alternative in the mix.
How about two Tables with a base class of Like, one CommentLikes and the other PostLikes Seeing that the size of this table will grow really fast, I'm thinking separating them would possibly be a good thing, Right?
I'd rather drop the "LikeType" and either have Comment and Post entity in the Like entity and distinguish by one of them being null or introduce two new entities
public class CommentLike
{
public Comment Comment { get; set; }
public Like Like { get; set; }
}
which holds a comment and a like and PostLike which holds a Post and a Like. The Comment then looks like this
public Comment
{
public virtual ICollection<CommentLike> { get; set; }
}
Another alternative is to create separate tables for comment and post likes. While what you ask for is definitely doable I would recommend more verbose but simpler solution which will result in code that is easier to maintain and has less bugs. Is there any specific reason you want to have a LikeType property?
I had same problem but didnt encounter an easy way.
class Post{
public virtual ICollection<Like> Likes {set;get;}
}
class Comment{
public virtual ICollection<Like> Likes {set;get;}
}
Then:
class Like{
//....
}
You dont need a bi-directional relationship. Do you have a case where you need to query Likes table? and if you do, you will have to manage parsing it as ENUM somewhere which can be an extension method.
EF will create Post_Id and Comment_Id implicityly in your table design. You wont be able to query it but you wont need to. IN my experience i never needed to.
My question is, can I have a setter function in the above line of code
where it would automatically set Comments and Posts for the Like type?
I assume you are using T4 template or the classes that were generated by EF are partialthen you can extend it by creating another partial class and a wrapper property for Likes
// Backing field
private ICollection<Like> _likesWrapper;
public ICollection<Like> LikesWrapper {
get {
// Lazy loading
if(_likes == null)
{
// Just create a new list or load it from the database.
_likes = new List<Like>();
}
return _likes;
}
set {
foreach(var val in value)
{
//Set the comment and posts
}
Likes = value;
}
I'm struggling with the design aspect of building this web site, its my first website and I'm not sure of the correct direction i need to take this project in. I've posted on this previously but not done a good job of explaining it. So I'll attempt to do so now.
The Site will be used for submitting "Innovation Ideas" from employees. It will have to connect up to an already existing MS Access Database. There will be two tables in this database that it has to communicate with.
The first one Is the InnovationSubmission Table which which looks similar to this :-
ID(Auto Generated),
Short Description,
Long Description,
Name,
Email Address,
Date(From Date.Time.Now()) - on Submission.
Team Name
Area (Area of Business)
The User will use a Web Form(View) to enter the details above, it will be validated, then saved to the back end database. I have this working in a fashion. The issue has started when I have tried to introduce two DropDownlistsFor contorls based on another table which is below :-
AREA A - Team1, Team3, Team5, Team7
AREA B - Team2, Team4, Team6, Team8
This is just sample Data, there are only two different areas in the table, but there will be over 50 teams split across them. I will be looking to have the Teams dropdownList filter on the value in the Area DropDownlist.
In my Models folder I have created a InnovationSubmission Class, that replicates the table in the database, this class is used as a strongly typed data type in the View representing the Submission Form. Its how i Validate the User input and I pass this class to a c# method that sends the data back using ADO.NET.
I'm struggling with how I should be trying to implement the dropdownlists.
Will I need to create a class similar to the InnovationSubmission Class, to represent the Teams/ Area Table?
Is the table at present structured in the best way for this project?
Can I populate both dropdownlists from the 1 table?
How do I relate the Teams & Area Columns?
Any Help would be greatly appreciated!?!
Would this be the correct way to design my View Model :-
public class MyViewModel
{
public int ID { get; set; }
public string shortDesc { get; set; }
public string longDesc { get; set; }
public string Status { get; set; }
public string originator { get; set; }
public string originatorEmail { get; set; }
public IEnumerable<Area> area { get; set; }
public IEnumerable<Team> team { get; set; }
}
public class Team
{
public string teamName { get; set; }
}
public class Area
{
public string area { get; set; }
}
You seem to be talking about cascading dropdown lists where the values of the second one update based on the selection made in the first one. I have illustrated an example of how this could be achieved in this post. The idea is that you subscribe to the .change event of the first dropdownlist and then trigger an AJAX request to a controller action passing the selected value in which you wold query the database and return a list of possible options.