How to change a button value from "buttonX" to "clicked" on clicked? - asp.net-core-mvc

This is a homework that I'll have to create a "x" amount of buttons and when I click on any button, it should change its value/label from "buttonX" to "clicked".
By clicking in another button, the first will reset to "buttonX" and the new button will change to "clicked".
So far I was able to create the "x" amount of buttons, but I dont know how to make them clickable to change its value back and forth.
Here's my model:
namespace buttonTag.Models {
public class Button {
private const int QTY_BTN = 10;
public Button() {
}
public int buttons {
get {
return QTY_BTN;
}
}
}
}
And this is my Razor page:
#model buttonTag.Models.Button;
<form asp-controller="Home" asp-action="Button">
<div class="form-group">
#{
for(int i=1; i<#Model.buttons + 1; i++) {
<input type="submit" value=#("Button" + i) class="btn btn-primary ml-4 mb-4" />
}
}
</div>
</form>
Any help?

Here is a simple workaround like below:
<form asp-controller="Home" asp-action="Button">
<div class="form-group">
#{
for (int i = 1; i < #Model.buttons + 1; i++)
{
<input type="button" id="#i" value=#("Button" + i) class="btn btn-primary ml-4 mb-4" onclick="Test(#i)" />
}
}
</div>
</form>
#section Scripts{
<script>
var item;
function Test(i) {
if (i != item) {
if (($("#" + i)).val().startsWith('Button')) {
$("#" + i).val("Clicked");
}
}
$("#" + item).val("Button" + item);
item = i;
return item;
}
</script>
}
Result:

Related

Bind multiple Dropdowns and retrieve user selction at postback

I'm working on an MVC Core form where a requester has to define some approvers for his application. When preparing the model for the Get request, I first get the roles for the approvers. Currently, there are always four roles returned:
Category Head
Governance Head
Concessions VP
Commercial EVP
And here is the HttpGet:
[HttpGet]
public async Task<IActionResult> Create()
{
// omitted for brevity...
// Get the SystemRole models (4 models will be returned)
model.ApprovingRoles = (await serviceLookup.GetAllRolesAsync(ct)).ToList();
}
The SystemRoleModel is simply:
public class SystemRoleModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
The view is composed of EditorTemplate as follows:
Create.cshtml -> LetterEditor.cshtml -> LetterAttachmentEditor.cshtml
Create.cshtml:
#model LetterModel
#{
ViewData["Title"] = "Create RL";
}
#Html.EditorFor(m => m, "LetterEditor", new { ShowApprovers = "1", ShowAttachments = "1", ShowButtons = "1" } )
LetterEditor.cshtml:
#model LetterModel
...
<div class="panel-body">
#await Html.PartialAsync("EditorTemplates/LetterAttachmentEditor", new LetterAttachmentUploadViewModel { IsBusy = false, LetterGuid = Model.IdCode.ToString() })
</div>
...
And finally, LetterAttachmentEditor.cshtml:
#model IList<SystemRoleModel>
#for (var i = 0; i < Model.Count; i++)
{
var index = i;
var title = Model[index].Name;
<div class="row">
<div class="col-lg-2 mt-3">
#Html.Label("LetterApprover[" + index + "]", title, new { #class = "control-label" })
</div>
<div class="col-lg-4">
#(Html.Kendo().DropDownList().Name("LetterApprover[" + index + "]")
.DataValueField(nameof(SystemUserModel.Id))
.DataTextField(nameof(SystemUserModel.EmployeeName))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsersByRoleId", "Api", new { roleId = Model[index].Id });
}).ServerFiltering(true);
})
)
</div>
<div class="col-lg-6">
<span asp-validation="" class="text-danger"></span>
#Html.ValidationMessage("LetterApprover[" + index + "]", $"An approver as a {title} is required", new { #class = "text-danger" })
</div>
</div>
}
Also, LetterModel.cs:
public class LetterModel
{
public LetterModel()
{
Approvers = new List<LetterApproverModel>();
}
// omitted for brevity...
public IList<SystemRoleModel> ApprovingRoles { get; set; } = new List<SystemRoleModel>();
}
Now, with that all out of the way, here is the final rendered dropdown (minus the kendo fluff):
<input id="ApprovingRoles_LetterApprover_0_" name="ApprovingRoles.LetterApprover[0]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_1_" name="ApprovingRoles.LetterApprover[1]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_2_" name="ApprovingRoles.LetterApprover[2]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
<input id="ApprovingRoles_LetterApprover_3_" name="ApprovingRoles.LetterApprover[3]" required="required" type="text" validationmessage="..." data-role="dropdownlist">
If the user submits this form, I need to receive a list of selected IDs from this array of dropdowns. I followed an anti-pattern, so I'm hoping the MVC binding will do its magic here. I just need to figure out the name of the model property that I should add of type List<string>.
How about try to change the name into name="LetterApprover[0]" and name="LetterApprover[1]" and name="LetterApprover[2]" and name="LetterApprover[3]" .
Then you could bind to List<string> LetterApprover
Update
Name is auto-appended by MVC due to sub-editor
How about add js codes to change the input name when you submit the form?
I try it like below, I first add class="form-control" to dropdownlist, add id="save" to button, then:
<script>
var items = document.getElementsByClassName("form-control");
$('#save').click(function () {
for (var i = 0; i < items.length; i++)
{
items[i].setAttribute("name", "LetterApprover")
}
});
</script>
Then bind to List<string> LetterApprover.
I was able to bind the selected values to a model's property upon submission by modifying the prefix added by the MVC engine:
#using DACRL.Domain.Models.BusinessObjects
#model IList<DACRL.Domain.Models.BusinessObjects.SystemRoleModel>
#{
ViewData.TemplateInfo.HtmlFieldPrefix = "";
}
#for (var i = 0; i < Model.Count; i++)
{
var index = i;
var name = "SelectedApprover[" + index + "]";
var title = Model[index].Name;
<div class="row">
<div class="col-lg-2 mt-2">
#Html.Label(name, title, new { #class = "control-label" })
</div>
<div class="col-lg-4">
#(Html.Kendo().DropDownList().Name(name)
.Size(ComponentSize.Medium).Rounded(Rounded.Medium).FillMode(FillMode.Outline)
.HtmlAttributes(new { style = "width: 100%" })
.DataValueField(nameof(SystemUserModel.Identifier))
.DataTextField(nameof(SystemUserModel.EmployeeName))
.OptionLabel("Select " + title).Filter(FilterType.Contains)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetUsersByRoleId", "Api", new { roleId = Model[index].Id, sequence = index + 1 });
}).ServerFiltering(true);
})
.Height(500))
</div>
<div class="col-lg-6">
<span asp-validation="" class="text-danger"></span>
#Html.ValidationMessage(name, $"An approver as a {title} is required", new { #class = "text-danger mt-2" })
</div>
</div>
}
The line ViewData.TemplateInfo.HtmlFieldPrefix = ""; allowed me to control the naming and the binding started workinfg

Umbraco BlogComment Create Ajax

Hello im trying to post my blog comments the function works. but the whole site refreshes inside the div, i tried playing around with the partialview in the controller but im not sure what to do can anybody here point me in the right directtion, i want div to refresh with ajax request not the whole site intro the div.
<!-- Blog Comments -->
<!-- Comments Form -->
<div class="well">
<h4>Leave a Comment:</h4>
#if (Members.GetCurrentLoginStatus().IsLoggedIn)
{
using (Html.BeginUmbracoForm("CreateComment", "CommentSurface", FormMethod.Post, new { #id = "comment-form" }))
{
// use this where every display profile image is needed
var user = User.Identity.Name;
var imgUrl = Url.Content("~/media/profileimage/" + user.Replace(".", "") + ".png");
<input name="CommentOwner" type="text" value="#Members.GetCurrentMember().Name" class="form-control hidden" readonly="readonly" />
<input name="ownerid" type="text" value="#Members.GetCurrentMember().Id" class="form-control hidden" readonly="readonly" />
<div class="form-group">
<textarea name="Message" rows="3" placeholder="Type your message here" class="form-control"></textarea>
</div>
<input name="profileimage" type="text" value="#imgUrl" class="hidden" readonly="readonly" />
<button type="submit" class="btn btn-primary">Submit</button>
}
}
else
{
<p> You are not logged in Register here</p>
}
</div>
<hr>
<!-- Posted Comments -->
<div class="blog-comments">
#Html.Partial("_BlogComments")
</div>
<!-- Comment -->
#section scripts {
<script>
$(function () {
// Find the form with id='well-form'
$('#comment-form').submit(function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (data) {
$(".blog-comments").html(data);
},
error: function (result) {
alert('Comment was not successful!');
}
});
// return false to cancel the form post
// since javascript will perform it with ajax
return false;
});
});
</script>
}
</div>
SurfaceController:
public class CommentSurfaceController : SurfaceController
{
[HttpPost, ValidateInput(false)]
public ActionResult CreateComment(CommentViewModel model)
//public PartialViewResult CreateComment(CommentViewModel model)
{
if (!ModelState.IsValid)
{
return CurrentUmbracoPage();
}
var contentService = Services.ContentService;
var newContent = contentService.CreateContent(DateTime.Now.ToShortDateString() + " " + model.CommentOwner, UmbracoContext.PageId.Value, "BlogComment");
newContent.SetValue("CommentOwner", model.CommentOwner);
newContent.SetValue("Message", model.Message);
newContent.SetValue("profileimage", model.profileimage);
newContent.SetValue("ownerid", model.ownerid);
//Change .Save if u want to allow the content before publish
contentService.SaveAndPublishWithStatus(newContent);
return RedirectToCurrentUmbracoPage();
//return PartialView("BlogComments", model);
}
public ActionResult DeleteComment(int commentid)
{
var service = ApplicationContext.Current.Services.ContentService;
var content = service.GetById(commentid);
service.Delete(content);
return RedirectToCurrentUmbracoPage();
}
}
Partial View:
#foreach (var item in Model.Content.Children().OrderByDescending(m => m.CreateDate))
{
<div class="media">
<a class="pull-left" href="#">
<img class="media-object" width="64" src="#item.GetPropertyValue("profileimage")" alt="profile image">
</a>
<div class="media-body">
<h4 class="media-heading">
#item.GetPropertyValue("CommentOwner")
<small>#item.CreateDate</small>
</h4>
#item.GetPropertyValue("Message")
</div>
#item.Id
</div>
if (Members.GetCurrentLoginStatus().IsLoggedIn)
{
if (#Members.GetCurrentMember().Id.ToString() == item.GetPropertyValue("ownerid").ToString())
{
#Html.ActionLink("Delete", "DeleteComment", "CommentSurface", new { commentid = item.Id }, null)
}
else
{
#*<p> not ur comment</p>*#
}
}
else
{
//blank cant delete comment if not logged in
}
}
The problem is that UmbracoSurfaceController is loosing his context if you are not rendering the complete page.
If you work with ajax, you should not render out html and post this back. Only POST the data and update your layout in javascript when you get a 200 (ok) back from the server.
To do so, use the UmbracoApiController. This is a WebApi controller allowing you to send back json (or xml) serialized data.
More information about the UmbracoApiController can be found in the documentation.

MVC3 boolean editor template with multiple controls for the same property

I'm using c#, MVC3, Razor and Zurb Foundation 4.
I have a custom editor template for boolean values that will show different UI for different input devices. (visibility is controlled by Foundation's hide-for / show-for css classes)
The problem is that because all of these UI elements are always on the page, only the values in the first one will get bound to the model on post back.
So I either need to find a way of actually removing the HTML for the hidden divs or find a way to use a true value from any of the three elements (they all default to false so whichever is set to true would be the visible one)
This is my Boolean.cshtml:
#model bool
#using System.Web.UI.WebControls
#using Helpers
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBoxFor(model => model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownListFor(model => model, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' checked />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".Off"' onclick=''>Off</label>
<input id='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' name='#ViewData.TemplateInfo.HtmlFieldPrefix' type='radio' />
<label for='#ViewData.TemplateInfo.HtmlFieldPrefix + ".On"' onclick=''>On</label>
</div>
</div>
Currently the checkbox works fine but the dropdown does not. (I always get false for my model property by the time I get back to the controller).
If I move the dropdown div before the checkbox then the dropdown works but the checkbox does not.
Note that I'm not sure about the touch element yet so it may be wrong anyway. I'm not bothered about getting that working until I have this problem sorted out.
I cooked up a brute force apporach syncronizing each of the inputs using javascript & jquery. Please post if you find a better way
TEST FORM
#using BooleanEditorTemplate.Controllers
#model bool
#{ var modelname = "mmm"; }
#using(Html.BeginForm("Index","Home")){
<div class="hide-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#Html.CheckBox(modelname, Model)
</div>
</div>
</div>
<div class="show-for-small">
<div class="hide-for-touch">
<div class="editor-field">
#{
List<BoolString> ynb = new List<BoolString>();
ynb.Add(new BoolString(false, "No"));
ynb.Add(new BoolString(true, "Yes"));
}
#Html.DropDownList(modelname, new SelectList(ynb, "Value", "Description"))
</div>
</div>
</div>
<div class="show-for-touch">
<div class="switch round">
<input id='#modelname' name='#modelname' type='radio' checked value="on"/>
<label for='#modelname' onclick=''>Off</label>
<input id='#modelname' name='#modelname' type='radio' value="off"/>
<label for='#modelname' onclick=''>On</label>
</div>
</div>
<input type="submit" value="OK"/>
}
TEST SCRIPT
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script>
$(function () {
$('[name="#modelname"]').change(
function () {
var id = $(this).attr("id");
var name = $(this).attr("name");
var checked = false;
switch (this.type)
{
case 'checkbox':
checked = $(this).is(":checked");
break;
case 'select-one':
checked = $(this).val().toUpperCase() == 'TRUE';
break;
case 'radio':
checked = $('input[type="radio"][name=' + name + ']:checked').val().toUpperCase() === 'ON';
break;
}
//checkbox
$('input[type="checkbox"][name="' + name + '"]').prop('checked', checked);
//select the select-one
if (checked)
$('select[name="' + name + '"]').val('True');
else
$('select[name="' + name + '"]').val('False');
//select the proper radio
if (checked)
$('input[type="radio"][name='+ name +'][value="on"]').prop("checked", true);
else
$('input[type="radio"][name=' + name + '][value="off"]').prop("checked", true);
});
});
</script>
and my test controler/classes setup
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index",true);
}
[HttpPost]
public ActionResult Index(Boolean mmm)
{
return null;
}
}
public class BoolString
{
public bool Value { get; set; }
public string Description { get; set; }
public BoolString(bool val, string desc)
{
this.Value = val;
this.Description = desc;
}
}
So this works on my box. I did have to make several modifications as I didn't test this within the editor framework. Undoutably, you'd have to make several more to adapt it back within the scope of your framework.

ajaxupload el is undefined

i haved trying to use ajax upload image. here is my code
$(function () {
var btnUpload = $('#post_pd_thumnail');
if ($("#id").val()) var post_id = $("#id").val();
else var post_id = 0;
new AjaxUpload(btnUpload, {
action: site_root_domain + "/product/upload_image/" + post_id,
name: 'file_upload',
onSubmit: function (file, ext) {
if ($('#post_pd_thumnail').val() != '') {
if (!(ext && /^(jpg|png|jpeg|gif)$/.test(ext))) {
jAlert(lang_error_upload_avatar, lang_alert_notice);
return false;
}
}
$('#preview').html('<img style="margin-left:45px;margin-top:45px;" border="0" width="16" height="11" src="' + site_root_domain + '/templates/images/icons/loading_2.gif" />');
},
onComplete: function (file, response) {
if (!response) {
jAlert(lang_error_upload_avatar, lang_alert_notice);
} else {
img_upload = 1;
$('#preview').html(response);
}
return;
}
});
});
And my HTML is:
<div id="preview">{$preview}</div>
<div class="fileupload">
<input type="file" name="post_pd_thumnail" id="post_pd_thumnail" value="" />
</div>
<input type="hidden" name="id" id="id" value="{$data['product']['post_id']}" />
and i got this error when upload image "el is undefined" and the function does not work correctly can anyone help me solve this problem please
Try to change the file element to button like,
<div class="fileupload">
<input type="button" name="post_pd_thumnail" id="post_pd_thumnail" value="" />
</div>
Here is the solution.
* Attaches event to a dom element
*/
function addEvent(el, type, fn){
// 610 BUG
if (el == undefined) return;
if (w.addEventListener){
el.addEventListener(type, fn, false);
} else if (w.attachEvent){
var f = function(){
fn.call(el, w.event);
};
el.attachEvent('on' + type, f)
}
}

file upload does not work in IE 8, IE 9

i have the following code to upload a file, which runs without error in mozilla firefox and google chrome but gives error in IE 8. Please provide solution. This is my view-
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<fieldset>
<div class="input_panelleft">
<div class="input_panellabel">
#Html.LabelFor(model => model.DrawingName)
</div>
<div class="input_panelinput">
#Html.EditorFor(model => model.DrawingName)
</div>
<div class="input_panellabel">
Upload Drawing
</div>
<div class="input_panelinput">
<input type="file" name='file' id='file' />
</div>
<div class="center">
<input type="submit" value="Upload" />
</div>
</div>
</fieldset>
}
and following code in controller-
[HttpPost]
public ActionResult Create(DrawingDocumentsModel model, HttpPostedFileBase file)
{
if (ModelState.IsValid)
{
if (file != null)
{
var documentNameParts = file.FileName.Split('.');
var documentExtension = documentNameParts.Last();
var documentNameOnly = String.Join(".", documentNameParts.Take(documentNameParts.Length - 1));
var filename = documentNameOnly + "." + documentExtension;
if (_drawingDocumentService.IsDrawingNameAvailable(filename))
{
var path = Server.MapPath("~/Uploads/");
var Filepath = Path.Combine(path, filename);
file.SaveAs(Filepath);
var drawingDocuments = new DrawingDocuments();
drawingDocuments.ProjectId = 1;
drawingDocuments.ProjectName = "Drawing Tag";
drawingDocuments.FileName = filename;
drawingDocuments.UploadedDate = System.DateTime.Now;
drawingDocuments.UploadedBy = _workContext.CurrentUserId;
if (model.DrawingName == "" || model.DrawingName == null)
{
ModelState.AddModelError("CustomError", "Please Enter Drawing Name");
}
else
{
drawingDocuments.DrawingName = model.DrawingName;
drawingDocuments.Path = ("/Uploads/" + filename);
_drawingDocumentService.InsertDrawingDocument(drawingDocuments);
return RedirectToAction("DrawingDocuments");
}
}
else
{
ModelState.AddModelError("CustomError", "Drawing With Same File Name Already Available");
}
}
else
{
ModelState.AddModelError("CustomError", "Please Select Drawing");
}
}
return View(model);
}

Resources