I have an app where students can register and login and having a field called city.
I'm trying to make a dropdown of cities so the student can pick which city he wants from there. It's a long list so I made a function in StudentService which will return array of strings and I'm trying to send it to the form using model.attribute but it's not working.
I tried using ajax and JQuery with external json file of the cities and it still didn't work even after I looked several questions here. If you have any idea how it is best to handle it please let me know.
here is the code so far and what I tried:
Service:
public class StudentService implements StudentInterfaceService {
// regular function of get, create, delete, update
public String [] getCities() {
String [] cities = { "lots of cities here };
return cities;
}
}
Controller:
public class RegistrationController {
#Autowired
private StudentService studentService;
public RegistrationController(StudentService studentService){
super();
this.studentService = studentService;
}
#ModelAttribute("student")
public StudentRegistration studentInfo() {
return new StudentRegistration();
}
#GetMapping
public String showRegistrationForm(Model model) {
String [] cities = studentService.getCities();
model.addAttribute("cities", cities);
return "registration";
}
#PostMapping
public String registerStudent(#ModelAttribute("student") StudentRegistration studentInfo) {
studentService.saveStudent(studentInfo);
return "redirect:/registration?success";
}
}
Html:
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="ISO-8859-1">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<!-- success message -->
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our awesome app!</div>
</div>
<h1>Registration</h1>
<form th:action="#{/registration}" method="post" th:object="${student}">
<div class="form-group">
<label class="control-label" for="username"> Username </label>
<input id="username" class="form-control" th:field="*{username}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="studentName"> Student Name </label> <input
id="studentName" class="form-control" th:field="*{studentName}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="password"> Password </label> <input
id="password" class="form-control" type="password"
th:field="*{password}" required autofocus="autofocus" />
</div>
<div class="form-group">
<select th:field="*{city}" th:each="city: ${cities}">
<option th:value="city" th:text="city"></option>
</select>
</div>
<div class="form-group">
<label class="control-label" for="phoneNum"> Phone Number </label> <input
id="phoneNum" class="form-control" th:field="*{phoneNum}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label"> Gender: </label>
<select th:field="*{gender}">
<option th:value="'Male'" th:text="Male"></option>
<option th:value="'Female'" th:text="Female"></option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Register</button>
<span>Already registered? <a href="/" th:href="#{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
I also tried using ajax in this way and it didn't work:
<script>
$.ajax({
url:'/cities',
type:'GET',
dataType: 'json',
success: function( json ) {
$.each(json, function(i, value) {
$('#cities').append($('<option>').text(value).attr('value', value.value));
});
}
});
</script>
EDIT:
Student model have these fields:
private String username;
private String studentName;
private String password;
private String city;
private String phoneNum;
private String gender;
I'm beginner in web designing with ASP.NET Core. I wrote a view component that has a form with some inputs related to a view model. One of these inputs is a file input (of the IFormFile datatype).
I want to submit this view model to an action of a controller (POST action), check the validity of model, return another view component if the model state is valid, and remain on this view component with this view model if model state is not valid.
This is my View Model: PricingViewModel.cs
public class PricingViewModel
{
[Display(Name = "Select a file")]
public IFormFile formFile { get; set; }
[Display(Name = "ColumnCode")]
[Required(ErrorMessage = "Enter {0} value, please")]
public string colCode { get; set; }
[Display(Name = "ColumnName")]
[Required(ErrorMessage = "Enter {0} value, please")]
public string colName { get; set; }
}
My View Component (controller): PricingComponent.cs
public class PricingComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("PricingView", pricing));
}
}
My View Component (view): PricingView.cshtml
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId"/>
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId"/>
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile"/>
</div>
<div class="form-group mt-4">
<input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
</div>
</form>
My Home Controller: HomeController.cs
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colCode", "Invalid Data");
return ViewComponent("PricingComponent", new { pricing = pricing }); // 1
}
else if (!int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colName", "Invalid Data");
return ViewComponent("PricingComponent", new { pricing = pricing }); //2
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return ViewComponent("PricingComponent", new { pricing = pricing }); //3
}
}
Plan A
The above approach is my primary plan.
Problem
If I use options of submit input tag (asp-action, asp-controller) like above, the view model sends correctly, but I don't know how to handle the validity of the model and remain on this view component. In the above code, when the ShowPricing action runs, if the model state is valid, the code works correctly, but when model is invalid (1,2,3), the PricingView doesn't show the validation summery, and just loads with current view model.
Plan B
I used AJAX to send the viewModel to the action and instead of showing the validation summary, I send an alert to the user with AJAX. I changed PricingView as following:
My View Component (view): PricingView.cshtml
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId"/>
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId"/>
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="fromFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile"/>
</div>
<script>
$(document).ready(function () {
$('#ShowPricingBtn').click(function () {
var _url = '#Url.Action("ShowPricing", "Home")';
var input = $("#MyInputFile").get(0).files[0];
$.ajax({
type: "POST",
url: _url,
data: {
formFile: input,
colCode: $("#colCode").val(),
colName: $("#colName").val(),
},
success: function (result)
{
var IsValid = $('body').find('[name="IsValidPricing"]').val();
if (IsValid)
{
$("#ShowExcelTable").html(result);
}
else {
alert("Invalid Data");
}
},
});
});
});
</script>
<div class="form-group mt-4">
<input type="submit" value="Show" id="ShowPricingBtn" />
</div>
</form>
Problem
In this code:
If the model state is not valid, the alert sends correctly, but
If the model state is valid, the formFile input doesn't send correctly to action and it's null in view model.
I don't know whether I should go with the original or the alternate approach these problems. Do you know where I'm going wrong?
Not sure how do you call view components,here are the working demos:
For PlanA
1.Create ViewComponents/PricingComponent.cs and ViewComponents/ShowPricingExcelComponent.cs.
public class PricingComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("PricingView", pricing));
}
}
public class ShowPricingExcelComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(PricingViewModel pricing)
{
return await Task.FromResult((IViewComponentResult)View("ShowPricingExcel", pricing));
}
}
2.Create Views/Shared/Components/PricingComponent/PricingView.cshtml.
#model PricingViewModel
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId" />
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId" />
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile" />
</div>
<div class="form-group mt-4">
<input type="submit" asp-action="ShowPricing" asp-controller="Home" value="Show" id="ShowPricingBtn" />
</div>
</form>
3.Create Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml.
<h1>Excel....</h1>
Project Structure:
4.Views/Home/Index.cshtml:
#await Component.InvokeAsync("PricingComponent")
5.HomeController:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colCode", "Invalid Data");
return View("Index", pricing);
}
if (!int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
ModelState.AddModelError("colName", "Invalid Data");
return View("Index", pricing);
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return View("Index", pricing); //3
}
}
}
Result:
For PlanB
1.Create ViewComponents/PricingComponent.cs and ViewComponents/ShowPricingExcelComponent.cs.
2.Create Views/Shared/Components/PricingComponent/PricingView.cshtml.
Firstly,it should be type="button" otherwise it will call twice to the backend.Secondly,what you did in ajax is not correct,more detailed explation you could refer to this answer.At last,you could not judge the modelstate by get the value of IsValidPricing value in your sucess function.Because the value you get is always be the data you first render the page,you cannot get the changed ViewBag value when ajax post back.
#model PricingViewModel
<form class="text-left" method="post" enctype="multipart/form-data">
<input name="IsValidPricing" type="hidden" value="#ViewBag.isValid" />
<div class="form-group text-left">
<label asp-for="colCode" class="control-label"></label>
<input asp-for="colCode" class="form-control" id="colCodeId" />
<span asp-validation-for="colCode" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="colName" class="control-label"></label>
<input asp-for="colName" class="form-control" id="colNameId" />
<span asp-validation-for="colName" class="text-danger"></span>
</div>
<div class="form-group text-left">
<label asp-for="formFile " class="control-label"></label>
<input type="file" accept=".xlsx, .csv" asp-for="formFile" id="MyInputFile" />
</div>
<div class="form-group mt-4">
#*it should be type="button"*#
<input type="button" value="Show" id="ShowPricingBtn" />
</div>
</form>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#ShowPricingBtn').click(function () {
var _url = '#Url.Action("ShowPricing", "Home")';
var input = $("#MyInputFile").get(0).files[0];
var fdata = new FormData();
fdata.append("formFile", input);
$("form input[type='text']").each(function (x, y) {
fdata.append($(y).attr("name"), $(y).val());
});
$.ajax({
type: "POST",
url: _url,
data: fdata,
contentType: false,
processData: false,
success: function (result)
{
console.log(result);
if (result==false)
{
alert("Invalid Data");
}
else {
$("#ShowExcelTable").html(result);
}
},
});
});
});
</script>
3.Create Views/Shared/Components/ShowPricingExcelComponent/ShowPricingExcel.cshtml.
<h1>Excel....</h1>
4.Views/Home/Index.cshtml:
#await Component.InvokeAsync("PricingComponent")
<div id="ShowExcelTable"></div>
5.HomeController:
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult ShowPricing(PricingViewModel pricing)
{
if (ModelState.IsValid)
{
int temp;
if (!int.TryParse(pricing.colCode, out temp)|| !int.TryParse(pricing.colName, out temp))
{
ViewBag.isValid = 0;
return Json(false);
}
else
{
ViewBag.isValid = 1;
// do something ...
return ViewComponent("ShowPricingExcelComponent"); //Call another view component
}
}
else
{
ViewBag.isValid = 0;
return Json(false);
}
}
}
Result:
I'm not able to reproduce your error. Your code, as presented, works as expected. A validation message is displayed.
To make it a working example, I've added a GET method first.
[HttpGet]
public IActionResult ShowPricing() => ViewComponent("PricingComponent", new { pricing = new PricingViewModel() });
Open the URL Home/ShowPricing
Fill out the form.
Send the form. And the validation message is displayed.
I am trying to display error/successful alert in the login panel. But sweet alert isn't displaying error/successful alert while first time writing wrong/correct password. I must to write one more time wrong password to showing sweet alert. I didn't understand why it is like this. I tried to inspect codes with breakpoint. In first time its going to Login.cshtml and although ViewBag.status is false its not going to if (ViewBag.status==false). Can someone help me?
Controller;
[HttpGet]
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(TBLUSER t)
{
var values = db.TBLUSER.FirstOrDefault(x => x.MAIL == t.MAIL && x.PASS == t.PASS);
bool status;
if (values != null)
{
FormsAuthentication.SetAuthCookie(values.MAIL, true);
status= true;
ViewBag.status = status;
Thread.Sleep(2500);
return RedirectToAction("Index", "Panel");
}
else
{
status = false;
ViewBag.status = status;
Thread.Sleep(2500);
return View();
}
}
View;
<div class="limiter">
<div class="container-login100">
<div class="wrap-login100 p-t-50 p-b-90">
<form class="login100-form validate-form flex-sb flex-w" method="post">
<span class="login100-form-title p-b-51">
LOGIN
</span>
<div class="wrap-input100 validate-input m-b-16" data-validate="Mail is required.">
<input class="input100" type="text" name="MAIL" placeholder="Mail">
<span class="focus-input100"></span>
</div>
<div class="wrap-input100 validate-input m-b-16" data-validate="Password is required.">
<input class="input100" type="password" name="SIFRE" placeholder="Password">
<span class="focus-input100"></span>
</div>
<div class="flex-sb-m w-full p-t-3 p-b-24">
<div class="contact100-form-checkbox">
<input class="input-checkbox100" id="ckb1" type="checkbox" name="remember-me">
<label class="label-checkbox100" for="ckb1">
Remember me
</label>
</div>
<div>
<a href="#" class="txt1">
Forgot pass?
</a>
</div>
</div>
<div class="container-login100-form-btn m-t-17">
<button class="login100-form-btn" id="btn1">
Login
</button>
#if (ViewBag.status == false)
{
<script>
$('#btn1').click(function () {
swal("Error", "Wrong password, please try again.", "error");
});
</script>
}
#if (ViewBag.status == true)
{
<script>
$('#btn1').click(function () {
swal("Information", "Successfully u have logged in.", "success");
});
</script>
}
</div>
<div style="margin-top:20px; margin-left:170px">
You dont have an acc? Create
</div>
</form>
</div>
</div>
</div>
The outcome of the scripts below is to have the HTML call the Java file, and have that Java file execute with the text that was extracted from the HTML text-boxes. I've made sure the API's (servlet, APEX) are correctly installed.
Java
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
#SuppressWarnings("serial")
public class webConnAPI extends HttpServlet {
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User temp = new User();
temp.setfname(request.getParameter("fname"));
temp.setlname(request.getParameter("lname"));
temp.setEmail(request.getParameter("email"));
temp.setPword(request.getParameter("pword"));
EmailServer addUser = new EmailServer();
addUser.Users.add(temp);
}
JavaScript Function Called by the button
<script>
function addData(){
try{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var data = xhr.responseText;
alert(data);
}
}
xhr.open('GET', 'webConnAPI', true);
xhr.send(null);
}catch(Excetpion){
alert('didnt work');
}
}
</script>
HTML
The Text boxes and the buttons.
<form name="form" action="${pageContext.request.contextPath}/webConnAPI" method="post">
<fieldset>
<legend>
<h2>
<!--Not Useful to Question-->
</h2>
</legend>
<div class="separator"></div>
<p>
<!-- not Important to Question-->
</p>
<p>
<label>Email</label>
<input type = "text"
id = "email"
value = "Email"
name = "email"/>
</p>
<p>
<label>Password</label>
<input type = "password"
id = "pword"
value = "password"
name = "pword"/>
</p>
<p>
<label>First Name</label>
<input type = "text"
id = "fname"
value = "First Name"
name = "fname"/>
</p>
<p>
<label>Last Name</label>
<input type = "text"
id = "lname"
value = "Last Name"
name = "lname"/>
</p>
<div>
<button type="submit" id="buttonJoin" onclick="addDate()">Join</button>
</div>
<div>
<button onclick="buttonLogin" type="submit" name="buttonLogin">Login</button>
</div>
<div>
<button onclick="buttonReset" type="reset" nwame="buttonReset">Reset</button>
</div>
</fieldset>
<div id="data"></div>
<div id="showDiv" style="display:none;">Thanks</div>
</form>
I really don't understand the problem and I would be very grateful if I could get some help. Thanks in advance.
<button type="submit" id="buttonJoin" onclick="addDate()">Join</button>
you misspelled addData() method in onClick event of Join Button.
I followed this link. In this site project will be working fine.but when i'm create new project by following this link UI will be opened but messgae passing not done.so please help me.
Html script:
#{
ViewBag.Title = "Chat";
}
<h2>Chat</h2>
<div id="divLogin" class="mylogin">
User Name:<input id="txtUserName" type="text" /><br />
<br />Password : <input id="txtPassword" type="password" /><br />
<input id="btnLogin" type="button" value="Login" />
<div id="divalarm"></div>
</div>
<div id="divChat" class="mylogin">
<input type="text" id="txtMessage" />
<input type="button" id="SendMessage" value="broadcast" />
<input type="hidden" id="displayname" />
<ul id="listMessages"></ul>
</div>
#section scripts {
<!--Script references. -->
<!--The jQuery library is required and is referenced by default in _Layout.cshtml. -->
<!--Reference the SignalR library. -->
<script src="~/Scripts/jquery.signalR-2.0.3.min.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="~/signalr/hubs"></script>
<!--SignalR script to update the chat page and send messages.-->
<script>
$(function () {
$("#divChat").hide();
$("#divLogin").show();
var IWannaChat = $.connection.chatHub;
IWannaChat.client.addMessage = function (name, message) {
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#listMessages').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
$("#SendMessage").click(function () {
IWannaChat.server.send($('#txtUserName').val(), $('#txtMessage').val());
});
$("#btnLogin").click(function () {
$("#divChat").show();
$("#divLogin").hide();
});
$.connection.hub.start();
});
// This optional function html-encodes messages for display in the page.
function htmlEncode(value) {
var encodedValue = $('<div />').text(value).html();
return encodedValue;
}
</script>
}
ChatHub.cs:
public void send(string username, string message)
{
Clients.All.addMessage(username, message);
}
public void send1(string message)
{
Console.WriteLine("hi");
}
Thanks.