Form containing with ViewComponent - asp.net-core

I couldn't figure out how to use ViewComponent inside form
The form is rendered correctly (value in the dropdown), but the model binding, when posting form, fail
This is the view
<form asp-action="" method="post">
<div asp-validation-summary="All"></div>
<div class="row">
<vc:periodi model="#(Model.Periodi)"></vc:periodi>
</div>
This is the ViewComponent
<div class="col-2">
#(Html.Kendo().DropDownListFor(a => a.Anno)
.DataTextField("Text")
.DataValueField("Value")
.BindTo(Model.Anni)
.HtmlAttributes(new { style = "width: 100%" }))
No matter what I choose in the dropdown, the variable Anno inside the Object Periodi of the Model is null
I checked the rendered HTML
<input id="Anno" name="Anno" ...
I think, based on my experience with MVC, that should be something like "Periodi.Anno" for the model binder to work.
Any suggestion?

As your experience, the name should be Periodi.Anno to bind the ViewComponent property.
As my test with input tag like below:
<input asp-for="Name" name="MVCSubModel.Name" class="form-control" />
I suggest you try :
#(Html.Kendo().DropDownListFor(a => a.Anno)
.DataTextField("Text")
.DataValueField("Value")
.BindTo(Model.Anni)
.HtmlAttributes(new { style = "width: 100%"; name = "Periodi.Anno" }))

Related

Blazor problem connecting the UI with the code

I'm using Blazor Server application in Visual Studio 2019. In the .razor page I have:
<div class="container">
<div class="row">
<div class="col-md">
<label for="ConnectionStringEdit" id="Label1">Connection String for destination</label>
</div>
<div class="col-md-7">
<input type="text" id="ConnectionStringEdit" name="ConnectionStringEdit" text=#ConnectDestination spellcheck="false" style="width: 585px; height: 26px;" class="form-control">
</div>
<div class="col-md-auto">
<input type="submit" id="btnConnect" name="btnConnect" value="Connect" class="btn btn-primary" #onclick="Connect1">
</div>
</div>
</div>
now in the code part I have
#code {
private string ConnectDestination { get; set; } = "";
private void Connect1()
{
if (ConnectDestination.Length > 0)
{
// do something
}
}
}
When I insert something in the Input and I press the button, ConnectDestination doesn't take the value of the Input Control. So this last If condition is never true. How do I get the inserted value of the Input control named ConnectionStringEdit?
Thanks
It should be #bind-value="#ConnectDestination"
you could also use the short directive #bind instead:
#bind="#ConnectDestination"
Note: All the input element's types are bound through the value attribute of the element.
Note: Both #bind-value and #bind are compiler directive instructing the compiler to emit code, behind the scene, that enables two way data-binding between a variable and an Html tag. The compiler create a two-way data binding by binding a variable to the value attribute of the element, something equivalent to this:
value="#ConnectDestination", which creates a one direction binding from the variable to the bound element. The compiler also creates an event call back which enables binding from the element to the variable, something equivalent to this:
#onchange="#((args) => ConnectDestination = args.Value?.ToString())"
This means that you could do that yourself, if you wish to have more control over the binding. You'll usually do something like this:
value="#ConnectDestination" #onchange="OnChange"
And define the call back method like this:
private void OnChange(ChangeEventArgs args)
{
// Note that it is your responsibility to update the
// ConnectDestination variable:
ConnectDestination = args.Value?.ToString());
}
Note: This is wrong:
<input type="submit" id="btnConnect" name="btnConnect" value="Connect" class="btn btn-primary" #onclick="Connect1">
The type attribute of the input element should be set to button:
<input type="button"
Blazor App is an SPA... meaning no submit. The only place you use the "submit" button is when you use the EditForm component, and even then the "submit" action is intercepted and canceled by the Blazor.
You can try
<input type="text" id="ConnectionStringEdit" name="ConnectionStringEdit" #bind=#ConnectDestination spellcheck="false" style="width: 585px; height: 26px;" class="form-control">
or
<input type="text" id="ConnectionStringEdit" name="ConnectionStringEdit" value="#ConnectDestination"
#onchange="#((ChangeEventArgs __e) => ConnectDestination = __e?.Value?.ToString())" spellcheck="false" style="width: 585px; height: 26px;" class="form-control">

Can't select chechbox with v-model in VueJS

I have a checkbox as a feature filter for a real estate agency site.
From the database comes the list of categories with their respective characteristics:
public function get_categories(Request $request)
{
$categories = Category::with('features')->get();
return response()->json([
'validation' => true,
'categories' => $categories
]);
}
In the Vue template, I have an accordion with UIKit.
I have one accordion header per category that I walk through using a v-for
Then inside the body of the accordion I have the checkboxes that correspond to the characteristics that belong to that category
<li
v-for="category in categories"
:key="category.id">
<a
href="#"
class="uk-accordion-title">
{{ category.name }}
</a>
<div class="uk-accordion-content">
<div uk-grid>
<div
class="uk-width-1-1 uk-margin-small"
v-for="feature in category.features"
:key="feature.id">
<label>
<input
:id="'feature_' + feature.id"
class="uk-checkbox"
type="checkbox"
name="features"
:value="feature.id"
v-model="features"
#change="filterUpdate"> <!-- ID hacer que este sea venga de la BD -->
{{ feature.name }}
</label>
</div>
</div>
</div>
</li>
To load the categories of course I have a method that is responsible for making the request when creating the component
layoutLoadCategories() {
axios.get('api/layout/get/categories').then( res => {
this.categories = res.data.categories;
});
},
The problem is that when I try to click on a checkbox, nothing happens. Not selected
When you are using v-model you no need to use :value and moreover since its a checkbox input you v-model variable should hold only boolean value (ie) either true or false
<input
:id="'feature_' + feature.id"
class="uk-checkbox"
type="checkbox"
name="features"
v-model="features" // here I guess features is an object or array...so assign a variable that is of type Boolean
#change="filterUpdate">
I have already worked out, in the form tag I had # click.prevent
I have removed the .prevent and it already works
Before:
<form id="filter_form" action="/property-browser" method="get" #click.prevent="filterUpdate">
After:
<form id="filter_form" action="/property-browser" method="get" #click="filterUpdate">

How to pass a dynamicy changed model to Partial view?

I have a list of "workbooks" displayed in a table. Each workbook has a "Share" button next to the workbook's title. When the user clicks on the share button a modal dialog is shown containing a form.
The form allows the user to enter a list of the recipient's emails separated by a comma which is validated on the client-side.
As the dialog is located in a partial view _ShareView.cshtml that allows me to pass a modal WorkbookShareModel that has some fields like WorkbookId and Title. The goal here is to pass the details of each workbook when the user presses the share button (i.e. construct a modal and pass it to the already rendered model).
I am not sure how to pass a model to an already rendered view?
The solution have to be done on the client (i.e. dont involve actions on the server that return the partial view provided the parameters are passed). I want to avoid unnesessary calls to the server - we have all the data on the client regarding a workbook and I need to do a POST when the user types in list of emails.
This is my index.cshtml:
#section BodyFill
{
<div id="shareFormContainer">
#{ await Html.RenderPartialAsync("_ShareView", new WorkbookShareModel());}
</div>
<div class="landing-container">
<div class="workbook-container">
<table class="table">
<tbody>
#foreach (var workbook in Model.Workbooks)
{
string trClassName, linkText;
if (workbook.Metadata.SharedBy == null)
{
trClassName = "saved-workbooks";
linkText = workbook.Name;
} else {
trClassName = "shared-with-me";
linkText = string.Format(
BaseLanguage.SharedWithMeWorkbook,
workbook.Name,
workbook.Metadata.SharedBy,
workbook.Metadata.SharedDate.ToShortDateString()
);
}
<tr class="#trClassName">
<td>#Html.ActionLink(linkText, "Open", "OpenAnalytics", new { id = Model.Id, workbook = workbook.Name })</td>
<td class="last-modified-date" title="Last Modified Date">#workbook.ModifiedDate.ToShortDateString()</td>
<td class="share">
<button title="Share" class="share-button" onclick='showSharingView("#workbook.Name", "#workbook.Id", "#Model.Id")'> </button>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
}
#section Scripts
{
<!--Load JQuery 'unobtrusive' validation -->
#await Html.PartialAsync("_ValidationScriptsPartial")
<script type="text/javascript">
// hide the modal as soon as the page loads
$('#shareFormModal').modal("hide");
function showSharingView(title, workbookId, id) {
$('#shareFormModal').modal("show");
// how to pass a WorkbookShareModel to my partial view from here?
}
function hideDialog() {
var form = $("#partialform");
// only hide the dialog if the form is valid
if (form.valid()) {
activateShareButtons();
$('#shareFormModal').modal("hide");
}
}
// Helper method that validates list of emails
function IsEmailValid(emailList, element, parameters) {
var SPLIT_REGEXP = /[,;\s]\s*/;
var EMAIL_REGEXP =
/^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+##[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/i;
var emails = emailList.split(SPLIT_REGEXP);
for (var i = emails.length; i--;) {
if (!EMAIL_REGEXP.test(emails[i].trim())) {
return false;
}
}
return true;
}
</script>
}
That is my dialog:
#using DNAAnalysisCore.Resources
#model DNAAnalysisCore.Models.WorkbookShareModel
#* Partial view that contains the 'Share Workbook dialog' modal *#
<!-- Modal -->
<div onclick="activateShareButtons()" class="modal fade" id="shareFormModal" role="dialog">
<div class="modal-dialog modal-md">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Share Workbook - #Model.Title</h4>
</div>
#using (Html.BeginForm("ShareWorkbook", "Home", FormMethod.Post, new { #id = "partialform" }))
{
<div class="modal-body">
<label>#BaseLanguage.Share_workbook_Instruction_text</label>
<div class="form-group">
<textarea class="form-control" asp-for="Emails" rows="4" cols="50" placeholder="#BaseLanguage.ShareDialogPlaceholder"></textarea>
<span asp-validation-for="Emails" class="text-danger"></span>
</div>
<input asp-for="Title" />
<input asp-for="Id" />
<input asp-for="WorkbookId"/>
</div>
<div class="modal-footer">
<button onclick="hideDialog()" type="submit" class="btn btn-primary">Share</button>
<button onclick="activateShareButtons()" id="btnCancelDialog" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
}
</div>
</div>
</div>
There are two solutions to solve your problem :
Option 1 :
Since you have got the parameters(title, workbookId, id) , you can call server side function using AJAX to render the partial view , then replace the DIV contained in the partial view with the updated contents in the callback function of AJAX .
You can click here for code sample .
Option 2 :
Directly update related input/area using Jquery . For example , the input tag helper :
<input asp-for="<Expression Name>">
generates the id and name HTML attributes for the expression name specified in the asp-for attribute. So you can set the value using Jquery like :
$("#Title").val("Title")
Please click here for Tag Helpers in forms in ASP.NET Core
With Option 2 , you need to clear the Emails area firstly after user click the share button ; With Option 1 , you don't need to care that since the HTML will replace entirely .

what is the use of insert mode on AJAXFORM in MVC?

When i am clicking the ajax from is loaded the partila view correctly inside the div have id as mytraget. But my question is what is the use of insertmode in ajax form.
On submitting the ajax form it always load the partial view inside of the div have id as mytraget on all type of insert mode. Then what is the of insert mode?
My original view named as MyView
#model Example.Models.mytest
<div id="mytraget"> </div>
#using(Ajax.BeginForm("myParialAjax", new AjaxOptions() { InsertionMode = InsertionMode.InsertBefore, UpdateTargetId = "mytraget" }))
{
<p>Name</p> #Html.TextBoxFor(m => m.string1)
<input type="submit" value="Submit" />
}
My Cobtroller Method
[HttpPost]
public PartialViewResult myParialAjax(mytest s)
{
return PartialView("Mypartial", s);
}
My Parial view which is named as Mypartial
#model Example.Models.mytest
<p>
#Html.TextBoxFor(m =>m.string1)
</p>
In all type of insert mode i get partial view inside of the the below div.
Output :
<div id="mytraget">
<p>
<input id="string1" type="text" value="asdf" name="string1">
</p>
</div>
I got myself the answer What i am missing is Need to insert some tags inside of the target tag.
Like below:
#model Example.Models.mytest
<div id="mytarget">
<p> my para </p>
</div>
#using(Ajax.BeginForm("myParialAjax", new AjaxOptions() { InsertionMode = InsertionMode.InsertBefore, UpdateTargetId = "mytarget" }))
{
<p>Name</p> #Html.TextBoxFor(m => m.string1)
<input type="submit" value="Submit" />
}
Now here InsertionMode.InsertBefore will insert my partial view above the paragraph tag and InsertionMode.InsertAfter will insert my partial view after the paragraph tag and InsertionMode.Replace will replace the whole things which is inside of the tag with my target id.

Working with multiple html helpers of same name in mvc4

I have multiple html helpers. When I click login button I am disabling user_register div using jquery and when I enter details the username and password the model binder is able to bind properly but when I click Register I am disabling user_login div and enabling user_register div and when I enter the details only email and firstname is what the model binder is able to bind and not username, password. Is this becoz I am using the same html helpers more than once. How to handle this. I have the following code
<div class="user_login">
<label>Email / Username</label>
#Html.TextBoxFor(model => model.Email)
<br />
<label>Password</label>
#Html.TextBoxFor(model => model.Password)
<br />
<div class="action_btns">
<div class="one_half"><i class="fa fa-angle-double-left"></i>Back
</div>
<div class="one_half last">
<input type="submit" style="border: none" name="action" class="btn btn_red" value="Login" />
</div>
</div>
Forgot password?
</div>
<div class="user_register">
<label>Full Name</label>
#Html.TextBoxFor(model => model.First_Name)<br />
<label>Email Address</label>
#Html.TextBox(model=>model.Email)<br />
<label>User Name</label>
#Html.TextBoxFor(model => model.User_Name)<br />
<label>Password</label>
#Html.TextBox(model=>model.Password") <br />
</div>
The controller follows here
public ActionResult Index(Customer customer, string Action)
{
//something here
}
You have not shown you complete view, but assuming all those controls are generated inside one form element, then all controls will post back unless you make the inputs disabled. If so, then the first input with name="Email" is bound and the second one is ignored by the DefaultModelBinder. (since the first one is only hidden, its value is probably empty). Your script needs to ensure that the 2 inputs in the login section are disabled, for example
#Html.TextBoxFor(model => model.Email, new { id = "login-email" })
and
$('#login-email').prop('disabled', true);
Note the id attribute so you can select the correct one (and prevent duplicate id's which is invalid html.
An alternative would be to create 2 separate forms.