Hidden form submit with model as parameter - javascript

I'm trying to figure out how to send the MVC Model to my ActionResult method, but the data on the AccountsManagementDetailsModel model is always empty or null, even though the model object itself is properly constructed, only with empty properties.
My method on the controller:
public async Task<ActionResult> ResetPassword(AccountsManagementDetailsModel model)
{
...
}
My JQuery:
var form = $('<form action="#Url.Action("ResetPassword", "AccountsManagement")" method="POST">');
var input = $("<input>")
.attr("type", "hidden")
.attr("name", "model").val(#Html.Raw(Json.Encode(Model)));
form.append(input + "</input></form>");
form.appendTo('body').submit();
My AccountsManagementDetailsModel:
public class AccountsManagementDetailsModel : UserInfo
{
public bool New { get; set; }
}
public class UserInfo
{
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[Display(Name = "Username")]
public string UserName { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
public bool Customer { get; set; }
public string CustomerID { get; set; }
public bool MustChangePassword { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd hh:mm}", ApplyFormatInEditMode = true)]
public DateTime? LastLogin { get; set; }
}
What am I doing wrong?

The right way to sent your model is create inputs for each property of your model. It could be difficult but you can use EditorTemplate that generate you html with assistance of HtmlHelpers.
The easiest way that i can see is to change your code like this:
var form = $('<form action="#Url.Action("ResetPassword", "AccountsManagement")" method="POST">' + formHtml + "</form>");
var formHtml = '#Html.Raw(Html.EditorForModel().ToString().Replace("\r\n", "<br />"))';
form.append(formHtml + "</form>");
form.appendTo('body').submit();
Helper EditorForModel should create valid inputs (with right name attributes) for you and allow you to post model to controller and bind it there.
Anyway if you don't want to change your code this way you can change your controller code like this:
public async Task<ActionResult> ResetPassword(string model)
{
AccountsManagementDetailsModel modelBind = new JavaScriptSerializer().Deserialize<AccountsManagementDetailsModel>(model);
}
This lines should deserialize your serialized string from Json to your model.

Related

HtmlAgilityPack how to get div that gets added by js?

Today I've wanted to write a webscraper that searches through a calendar website and finds the tags of events, so I can search through them and get info about who worked for the event.
The Problem is: The div I want to search for gets added by js, so how do I get it with htmlagilitypack?
The Calendar Website: https://esel.at/termine
My Code:
using System;
using HtmlAgilityPack;
using System.Linq;
using System.Diagnostics;
using System.Threading;
namespace ESEL_Scraper
{
class Program
{
static void Main(string[] args)
{
string Url = $"https://esel.at/termine";
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(Url);
HtmlNode[] nodes = doc.DocumentNode.SelectNodes("//div[#class='content']").ToArray();
for(int i = 0; i < nodes.Length; i++) {
Console.WriteLine(nodes[i].InnerText);
}
}
}
}
SelectNodes returns null when it doesn't find what you're looking for. So that's why you get the null exception. There are no "div" elements with class = "content". If you change to a class that is used by a div element on that page you'll get results.
With HtmlAgility pack "SelectNodes" you need to do a null check in some way before using the result.
Short anwser: You can't. Parsing the web page for data, that gets added when the page loads is not possible by using HtmlAgilityPack - the initial source code of the page doesn't have the data.
Long anwser: There is probably some API call that gets the data for the events, and is then pushed via javascript to the page. Try to figure out what URL is used, and try to parse that. That would be this one: https://esel.at/api/termine/data?date=05.09.2020&selection=false
As it's stated Javascript append the content. Using basic network inspecting you will see that there is another network request.
What you get here is data in JSON format which gets appended in HTML using Javascript.
Instead of using HtmlAgility pack you will need to parse JSON. In the example below I have used Newtonsoft.Json package to do that.
Here is the code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
namespace ESEL_Scraper
{
internal class Program
{
private static void Main(string[] args)
{
//Simply create request to the API and deserialize JSON using the Root class
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
CookieContainer cookies = new CookieContainer();
// Set the date you want in the link, in this example it's 06.09.2020
var request = (HttpWebRequest)WebRequest.Create("https://esel.at/api/termine/data?date=06.09.2020&selection=false");
request.CookieContainer = cookies;
request.Method = "GET";
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36";
request.ContentType = "application/json";
request.Headers.Add("accept-language", "en,hr;q=0.9");
request.Headers.Add("accept-encoding", "");
request.Headers.Add("Upgrade-Insecure-Requests", "1");
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string responseFromServer = reader.ReadToEnd();
reader.Close();
response.Close();
//Deserialize Json
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(responseFromServer);
foreach (var el in myDeserializedClass.termine)
{
//Get any field you need
Console.WriteLine(el.title);
Console.WriteLine(el.location);
}
Console.ReadLine();
}
}
// Based on the JSON response https://pastebin.com/Xa5gSp50 I have generated classes using this website: https://json2csharp.com/
public class Termine
{
public int id { get; set; }
public string title { get; set; }
public string category { get; set; }
public string startdate { get; set; }
public string startdatetime { get; set; }
public string starttime { get; set; }
public string enddate { get; set; }
public List<object> runtime { get; set; }
public string thumbnail { get; set; }
public string thumbnail_credits { get; set; }
public string type { get; set; }
public string recommended { get; set; }
public bool online_event { get; set; }
public object feed_urls { get; set; }
public string status { get; set; }
public string tags { get; set; }
public string url { get; set; }
public string sort_date { get; set; }
public string sort_category { get; set; }
public string location_url { get; set; }
public string location { get; set; }
}
public class Meta
{
public List<string> next { get; set; }
public DateTime now { get; set; }
public List<string> date { get; set; }
public DateTime end { get; set; }
public DateTime runtime { get; set; }
public int upcoming { get; set; }
public int running { get; set; }
public int termine { get; set; }
}
public class Root
{
public List<Termine> termine { get; set; }
public Meta meta { get; set; }
}
}

How do I construct this json string and take its values in the action method? (scenario provided)

image
In the image link above I have created a form which can dynamically add more rows of input fields
The values from the input field that are dynamically added are pushed into an array while the values on the green part are place into a javascript object.
reservations.push({ Day:d, Room: r, TimeIn: datetimeIn.toString(), TimeOut: datetimeOut.toString()});//this is assuming that only 1 row of input field was added
var r = JSON.stringify(reservations);
//There's only 1 course, description, section, datefrom and dateto while there can be many Day, Room, TimeIn, TimeOut.
var reservation = { CourseCode: courseCode.val(), Description: description.val(), Section: section.val(), DateFrom: dateF, DateTo: dateT, r };
$.ajax({
url: '/ReserveSubject',
type: 'POST',
data: 'reservation=' + JSON.stringify(reservation),
How do I take the values of the json string and create and instance of an object that will take those values
[HttpPost]
public ActionResult ReserveSubject(string reservation)
{
Subject sub = new Subject();
sub.CourseCode = reservation.CourseCode;
sub.Description = reservationDescription;
.
.
.
//loop through reservation data from dynamically added rows of input field
{
Schedule sch = new Schedule();
sch.Day = reservation.Day;
sch.Room = reservation.Room;
.
.
.
sub.Schedule.add(sch);
}
sub.ScheduleTable = MethodThatWillConvertScheduleListToDatatable(sub.Schedule);
}
Object to instantiate
public class Subject
{
string CourseCode { get; set; }
string Description { get; set; }
string Section { get; set; }
string DateFrom { get; set; }
string DateTo { get; set; }
List<Schedule> Schedule { get; set; }
DataTable ScheduleTable { get; set; }
}
public class Schedule
{
string Day { get; set; }
string Room { get; set; }
string TimeIn { get; set; }
string Timeout { get; set; }
}
I have already downloaded NewtonSoft as i think most of your answer will make use of it.
var jsonObject = {
"Prop1" : "something",
"Prop2" : "something",
"Prop3List" : GetSomeJsonScheduleList()
etc...
};
public class ExampleModel
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
public IList<Schedule> Prop3List {get; set;}
}
public ActionResult ControllerMethod(ExampleModel model)
{
//Use your model like normal
}
Then just JSON.stringify(jsonObject) in your ajax call.
Take note of the naming conventions.

Converting MVC Model List to JSLINQ Error

I have three dropdownlist BodyPart, ExamDetail and ExamView and I have complete data set for these lists. I don't need to call controller again and again whenever the dropdown change event call but I want to fetch list from my model's property list. I am using JS Library to apply LINQ Queryto avoid any loops in code.
My Class Architecture is given below:
public class BodyPart
{
public string ID { get; set; }
public string Text { get; set; }
public List<ExamDetail> examdetail { get; set; }
}
public class ExamDetail
{
public string ID { get; set; }
public string Text { get; set; }
public List<ExamView> examview { get; set; }
}
public class ExamView
{
public string ID { get; set; }
public string Text { get; set; }
}
I have proper data in all my list, here is my js code to fetch ExamDetail Record
var selectedBodyPart = $("#BodyPartDDL").val();
var examdetailList = JSLINQ(#Model.bodypart).Where(function (item) {
return item.ID == selectedBodyPart; });
But I am getting "Uncaught SyntaxError: Unterminated template literal(…)" error where I pass my model list. I need to pass this examdetailList to my ExamDetail partial view. Thank you.

Client side validations not working in Internet Explorer 9

I just created mvc 4 Application .In that application I have a form to insert department. for that form I'm using client side validations.
these client side validations properly working in Firefox and Chrome , but not in IE 9 (Internet Explorer)
This is my model class
public partial class tbl_hec_Department
{
public tbl_hec_Department()
{
this.tbl_hec_level_of_Study = new HashSet<tbl_hec_level_of_Study>();
this.tbl_hec_Programme = new HashSet<tbl_hec_Programme>();
}
[Required]
[DisplayName("Department ID")]
[Remote("doesDepartment_IDExist", "HEC", HttpMethod = "POST", ErrorMessage = "Department ID already exists.")]
public string Department_ID { get; set; }
[Required]
[DisplayName("Name of Department")]
public string Name_of_Department { get; set; }
[DataType(DataType.PhoneNumber)]
[DisplayName("Telephone Number")]
//[StringLength(50, ErrorMessage = "Please enter a minimum of {2} characters", MinimumLength = 6)]
public string Contact_General_Line { get; set; }
//[StringLength(50, ErrorMessage = "Please enter a minimum of {2} characters", MinimumLength = 6)]
[DisplayName("Fax Number")]
public string Contact_Fax_Number { get; set; }
[Required]
[EmailAddress(ErrorMessage = "Please enter a valid email address")]
[DisplayName("Email Address")]
public string Contact_Email { get; set; }
[Required(ErrorMessage = "Please select the {0}")]
[DisplayName("University / Institute")]
public string HEI_ID { get; set; }
[Required(ErrorMessage = "Please select the {0}")]
[DisplayName("College")]
public string College_ID { get; set; }
[DisplayName("Status")]
public Nullable<bool> Status { get; set; }
public string Create_By { get; set; }
public Nullable<System.DateTime> Create_Date { get; set; }
public string Update_By { get; set; }
public Nullable<System.DateTime> Update_Date { get; set; }
public virtual tbl_hec_College tbl_hec_College { get; set; }
public virtual tbl_hec_University tbl_hec_University { get; set; }
public virtual ICollection<tbl_hec_level_of_Study> tbl_hec_level_of_Study { get; set; }
public virtual ICollection<tbl_hec_Programme> tbl_hec_Programme { get; set; }
}
theses are the scripts files in Scripts Folder
this is how i render script files in layout files
#Scripts.Render("~/Scripts/jquery.min.js")
#Scripts.Render("~/Scripts/jquery-migrate-1.2.1.js")
#Scripts.Render("~/Scripts/bootstrap.min.js")
#Scripts.Render("~/Scripts/jquery-ui.min.js")
#Scripts.Render("~/Scripts/raphael-min.js")
#Scripts.Render("~/Scripts/morris.min.js")
#Scripts.Render("~/Scripts/jquery.sparkline.min.js")
#Scripts.Render("~/Scripts/jquery-jvectormap-1.2.2.min.js")
#Scripts.Render("~/Scripts/jquery-jvectormap-world-mill-en.js")
#Scripts.Render("~/Scripts/jquery.knob.js")
#Scripts.Render("~/Scripts/daterangepicker.js")
#Scripts.Render("~/Scripts/bootstrap-datepicker.js")
#Scripts.Render("~/Scripts/bootstrap3-wysihtml5.all.min.js")
#Scripts.Render("~/Scripts/icheck.min.js")
#Scripts.Render("~/Scripts/app.js")
#Scripts.Render("~/Scripts/dashboard.js")
#Scripts.Render("~/Scripts/demo.js")
I'm pretty sure that in client machine browser java script is disabled. First you check whether java script is enabled or disabled in client browser. You can check it programatically using this code.
public static bool IsJavascriptEnabled( )
{
bool retVal = true;
//get the registry key for Zone 3(Internet Zone)
Microsoft.Win32.RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\3", true);
if (key != null)
{
Object value = key.GetValue(DWORD_FOR_ACTIVE_SCRIPTING, VALUE_FOR_ENABLED);
if( value.ToString().Equals(VALUE_FOR_DISABLED) )
{
retVal = false;
}
}
return retVal;
}
You can also visit this link How to check java scxript in client browser enabled or not

How to select object in dropdown

I have a City class
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
}
and Ride class.
public class Ride
{
public Guid Id { get; set; }
public City From { get; set; }
public List<City> To { get; set; }
public DateTime DateAndTime { get; set; }
}
What is the best way to load cities, pass it to view, show them in dropdownlists and POST data back to controller? Best would be if I could add more than one City to To column.
I have found Selectize.js but I have no experience with JavaScript. Can I pass to options only JSON etc or could it be a list of cities from database.
Thank you for your time.
You'll need a view model, especially if you want to select multiple cities at once. For example:
public class RideViewModel
{
public Guid Id { get; set; }
public DateTime DateAndTime { get; set; }
public int FromCityId { get; set; }
public List<int> ToCityIds { get; set; }
public IEnumerable<SelectListItem> CityChoices { get; set; }
}
Notice that there's no List<City> property on the view model. Instead, there's ToCityIds which will store the selected id values from the list box and CityChoices which will be used to populate the list box. You can't post full City objects from a list box, only simple types like int. So, on POST you'll use the values from ToCityIds to lookup up the City instances from the database. The same goes for your From property on your entity.
Now, in your controller:
private void PopulateCityChoices(RideViewModel model)
{
model.CityChoices = db.Cities.Select(m => new SelectListItem
{
Value = m.Id,
Text = m.Name
});
}
public ActionResult Create()
{
var model = new RideViewModel();
PopulateCityChoices(model);
return View(model);
}
[HttpPost]
public ActionResult Create(RideViewModel model)
{
if (ModelState.IsValid)
{
// Create new `Ride` and map data over from model
var ride = new Ride
{
Id = Guid.NewGuid(),
DateAndTime = model.DateAndTime,
From = db.Cities.Find(model.FromCityId),
To = db.Cities.Where(m => m.ToCityIds.Contains(m.Id))
}
db.Rides.Add(ride);
db.SaveChanges();
}
// Must repopulate `CityChoices` after post if you need to return the form
// view again due to an error.
PopulateCityChoices(model);
return View(model);
}
Finally in your view change the model declaration to:
#model Namespace.To.RideViewModel
And then add your From select list and To list box:
#Html.DropDownListFor(m => m.FromCityId, Model.CityChoices)
#Html.ListBoxFor(m => m.ToCityIds, Model.CityChoices)
You can use the same choices for both, since they're both selecting cities.

Categories

Resources