Set path of selected file to model in view - javascript

I am trying to set the full path of the selected file into the model in the view.
Controller FileController:
public async Task<IActionResult> Create(CreateFileViewModel model)
{
if (ModelState.IsValid)
{
var file = new File
{
Path = model.Path
};
_context.Add(file);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(model);
}
Model CreateFileViewModel:
public class CreateFileViewModel
{
public string Path { get; set; }
}
Model File:
public class File
{
public int Id { get; set; }
public string Path { get; set; }
}
ViewForm Create:
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Path" class="control-label"></label>
<input asp-for="Path" id="selectedFile" type="file" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
Script in Create:
<script>
document.getElementById('selectedFile').onmouseout = function () {
#Model.Path=this.value;
};
</script>
But
#Model.Path=this.value;
this not working. Ofc I cannot convert between razor and javascript variables. But I don't know another way how to set full path of selected file into the model variable.
This
<input asp-for="Path" id="selectedFile" type="file" />
set into model variable just file name, without a path.

#Model.Path is server side i.e. c# code, while this.value is java script code which is client side code, so the server side code will get executed when view is rendered while your js code with execute on particular event in your html.
What you need is to update the hidden value via javascript and it will post back in controller with updated value and will also work in html with the updated value.
Your hidden field will be rendered with id Path, so you can write :
document.GetElementById("Model").value = this.value;
or if you have jquery library included in your application, then you can make use of that as well:
$("#Path").val(this.value);
This way when the model will get posted back to controller, the Path property will have the updated value which would be the path you have assigned via js code.
Hope it helps!

Related

Using C# MVC multiple dynamic models in View

I have a View with several form that I'm using for searching and displaying the results as partial View in like SearchByNumber, SearchByVehicle, etc.
I'm trying to load view and execute search for different forms by posting link with querystring like www.example.com/Search?number=101010 from different view.
For the first form, SearchByNumber I only have one parameter, string number and i'm returning view with dynamic Model and its working like it should, but I only manage to make search for this form.
Here is my controller:
public ActionResult Index(string number)
{
return View(model: number);
}
and in the View I have:
<form id="searchbynumberform">
Search By Any Number:
<div class="input-group input-group-sm">
<input type="text" class="form-control" name="number" id="number" value="#Model">
<span class="input-group-btn">
<button class="btn btn-primary" type="button" name="numbersearch" id="numbersearch" disabled>
Search
</button>
</span>
</div>
</form>
My Question is, if anyone can help me, How to perform search let's say on the second form where I have int type and string name parameters?
Thank You in advance...
At the moment your Model is only the search string that was entered, which seems rather incomplete. It would make a lot more sense if the Model also contained the actual search results, which after all is what the user wants to see. And then you can also add the other search properties.
The MVC approach for this is to create a (View)Model class, somewhere in your project, something like this:
public class SearchModel
{
public string Number { get; set; }
public int? Type { get; set; }
public string Name { get; set; }
public List<SearchResult> SearchResults { get; set; }
}
And then use it e.g. like this:
public ActionResult Index(string number)
{
var model = new SearchModel
{
Number = number,
SearchResults = GetByNumber(number)
};
return View(model);
}
public ActionResult IndexOther(int type, int name)
{
var model = new SearchModel
{
Type = type,
Name = name,
SearchResults = GetByTypeAndName(type, name)
};
return View(model);
}
And in your Index.cshtml:
#model SearchModel
#* You can now use Model.Number, Model.Type, Model.Name and Model.SearchResults. *#

Prevent javascript firing on load page

I have MVC application with JavaScript in the body of the cshtml page. In Model, I have a method that returns a string, and I want that string to add in some div on a page on click of a button. It works, but, the method is triggered every time I load the page (and I want it to be triggered only on click.
Here is code:
Model:
public class TestJS
{
public string Tekst1 { get; set; }
public string Tekst2 { get; set; }
public TestJS()
{
Tekst1 = "one";
Tekst2 = "two";
}
public string AddTekst()
{
return "three (additional text from method)";
}
}
Controller:
public class TestJSController : Controller
{
// GET: TestJS
public ActionResult Index()
{
Models.TestJS tjs = new Models.TestJS();
return View(tjs);
}
}
View:
#model TestJavaScript.Models.TestJS
#{
ViewBag.Title = "Index";
}
<script type="text/javascript">
function faddtekst() {
whr = document.getElementById("div3");
var t = '#Model.AddTekst()';
whr.innerHTML += t;
}
</script>
<h2>Testing JavaScript Firing</h2>
<p>
First to fields:
#Model.Tekst1;
<br />
#Model.Tekst2;
</p>
<form>
<input type="button" value="Click to show Tekst3" onclick="faddtekst()" />
</form>
<br />
<hr />
<div id="div3">
</div>
I tried to wrap JS in $(document).ready() with same result.
Somebody may think of this as a strange approach, but, a model method that I'm trying to execute takes over 10 seconds in real code, so, I want to prevent waiting every time page loads (waiting should be only if the user clicks button).
The strangest thing is that Model.AddTekst() is executed EVEN if I comment it in javascript function with '//'.
Anyone knows how to avoid unwanted execution of Model.Method?
The behavior you are experiencing is not strange at all. #Model.AddText() executes on the backend once the view is compiled which is normal behaviour.
A comment in razor would look like this
#* Comment goes here *#
But this is not what you want to achieve.
I'm afraid your approach wont work since you can't execute a method on a model asynchronously.
I suggest you take a look at Ajax.BeginForm - more info here
You could implement a controller action on the backend which would return the text you want to display on the submitting of the form.
Try to use e.preventDefault() for button click.
<form>
<input type="button" value="Click to show Tekst3" id="Show" />
</form>
Try with jQuery
$(document).on("click", "#Show", function (e) {
e.preventDefault();
faddtekst();
});

How can I generate a PartialView for each click of a button? [duplicate]

The problem I will be describing is very similar to ones I already found (e.g. this post with nearly identical name) but I hope that I can make it into something that is not a duplicate.
I have created a new ASP.NET MVC 5 application in Visual Studio. Then, I defined two model classes:
public class SearchCriterionModel
{
public string Keyword { get; set; }
}
public class SearchResultModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
Then I created the SearchController as follows:
public class SearchController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult DisplaySearchResults()
{
var model = new List<SearchResultModel>
{
new SearchResultModel { Id=1, FirstName="Peter", Surname="Pan" },
new SearchResultModel { Id=2, FirstName="Jane", Surname="Doe" }
};
return PartialView("SearchResults", model);
}
}
as well as views Index.cshtml (strongly typed with SearchCriterionModel as model and template Edit) and SearchResults.cshtml as a partial view with model of type IEnumerable<SearchResultModel> (template List).
This is the Index view:
#model WebApplication1.Models.SearchCriterionModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SearchCriterionModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Keyword, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Keyword, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Keyword, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="button" id="btnDisplaySearchResults" value="Search" onclick="location.href='#Url.Action("DisplaySearchResults", "SearchController")'" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<div id="searchResults">
</div>
As you can see, I added a div with id="searchResults" below the standard template and edited the button. What I want is to display the partial view SearchResults.cshtml in the div on the bottom, but only after the button is clicked. I have succeeded in showing a partial view there by using #Html.Partial("SearchResults", ViewBag.MyData), but it is rendered when the parent view is loaded for the first time and I set ViewBag.MyData in the Index() method already, which is not what I want.
Summary: On clicking the button, I will obtain some List of SearchResultModel instances (via database access) and then the partial view should be rendered, using this newly obtained data as model. How can I accomplish this? I already seem fail at the first step, that is reacting to the button click with the above code. Right now, I navigate to the URL ~/Search/DisplaySearchResults, but of course there's nothing there and no code-behind method is called.
In traditional ASP.NET I'd just have added a server-side OnClick handler, set the DataSource for a grid and show the grid. But in MVC I already fail with this simple task...
Update: Changing the button to #Html.ActionLink I can finally enter the controller method. But naturally since it returns the partial view, it's displayed as the whole page content. So the question is: How do I tell the partial view to be rendered inside a specific div on the client side?
Change the button to
<button id="search">Search</button>
and add the following script
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('#search').click(function() {
var keyWord = $('#Keyword').val();
$('#searchResults').load(url, { searchText: keyWord });
})
and modify the controller method to accept the search text
public ActionResult DisplaySearchResults(string searchText)
{
var model = // build list based on parameter searchText
return PartialView("SearchResults", model);
}
The jQuery .load method calls your controller method, passing the value of the search text and updates the contents of the <div> with the partial view.
Side note: The use of a <form> tag and #Html.ValidationSummary() and #Html.ValidationMessageFor() are probably not necessary here. Your never returning the Index view so ValidationSummary makes no sense and I assume you want a null search text to return all results, and in any case you do not have any validation attributes for property Keyword so there is nothing to validate.
Edit
Based on OP's comments that SearchCriterionModel will contain multiple properties with validation attributes, then the approach would be to include a submit button and handle the forms .submit() event
<input type="submit" value="Search" />
var url = '#Url.Action("DisplaySearchResults", "Search")';
$('form').submit(function() {
if (!$(this).valid()) {
return false; // prevent the ajax call if validation errors
}
var form = $(this).serialize();
$('#searchResults').load(url, form);
return false; // prevent the default submit action
})
and the controller method would be
public ActionResult DisplaySearchResults(SearchCriterionModel criteria)
{
var model = // build list based on the properties of criteria
return PartialView("SearchResults", model);
}
So here is the controller code.
public IActionResult AddURLTest()
{
return ViewComponent("AddURL");
}
You can load it using JQuery load method.
$(document).ready (function(){
$("#LoadSignIn").click(function(){
$('#UserControl').load("/Home/AddURLTest");
});
});
source code link

Bind multiple files to array with properties

I have a basic HTML form with <input type="file" multiple> inside. For each chosen file I create a description.
Now I want to bind them to PostedPhotoViewModel[] PostedPhotos;:
public abstract class PostedPhotoViewModel
{
public string Description { get; set; }
public HttpPostedFileBase File { get; set; }
}
I don't know how to prepare my input to do such a thing. Is it possible? Or do I have to do some tricks to achieve my target?
#Html.TextBoxFor(m => m.PostedPhotos, new { #name = "PostedPhotos", type = "file", multiple="multiple" })
I tried to force it in such a way, but didn't work:
myForm.submit(function(e) {
myInput.files = $.map(myInput.files, function(element) {
return {File: element, Description: "Test description"}
});
return true;
});
It's basic ASP.NET MVC 5 project.
I would replace this:
#Html.TextBoxFor(m => m.PostedPhotos, new { #name = "PostedPhotos", type = "file", multiple="multiple" })
With just:
<input type="file" name="files" multiple="multiple" />
Then in the controller do something like:
[HttpPost]
public ActionResult Index(IEnumerable<HttpPostedFileBase> files)
I think the nested view model list binding with a textbox property is making it far more complicated than it is.

Submitting form by AngularJs in spring mvc

I am new to Angularjs and trying to save table by using angularjs in spring mvc.
My table and controller is :
#Entity
public class StudentSkills {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int skillId;
private String skillName;
private int expMonth;
private int expYear;
private String experties;
#ManyToOne
#JoinColumn(name= "student")
#JsonIgnore
private Student student;
// Getters Setters
My jsp page is : The Angularjs Coding is probably not correct
<script>
var skillApp = angular.module('skillApp', []);
skillApp.controller('skills', function($scope, $http) {
$scope.refreshSkill = function(){
$http.get('/user/getuserskills')
.success(function(data) {
$scope.allSkills = data;
});
};
$scope.addSkill = function(skill){
$http.put('/user/addskill/'+skill)
.success($scope.refreshSkill());
};
});
</script>
<title>Add Skill</title>
</head>
<body>
<div ng-app="skillApp">
<div ng-controller="skills" ng-init="refreshSkill()">
<div ng-repeat="skill in allSkills">
<div class="col-sm-6 col-lg-3">
<div class="thumbnail">
<div class="caption">
<h5>Name : {{skill.skillName}}</h5>
<h5>Name : {{skill.expMonth}}</h5>
<h5>Name : {{skill.expYear}}</h5>
<h5>Name : {{skill.experties}}</h5>
</div>
</div>
</div>
</div>
<form novalidate ng-submit="addSkill(skill)">
<input type="text" ng-model="skill.skillName">
<input type="text" ng-model="skill.expMonth">
<input type="text" ng-model="skill.expYear">
<input type="text" ng-model="skill.experties">
<input type="button" id="submit" value="Submit">
</form>
</div>
</div>
</body>
My Controller is :
#RequestMapping(value= "getuserskills", method = RequestMethod.GET)
public #ResponseBody List<StudentSkills> getStudentSkills(Model model){
List<StudentSkills> skills = studentService.getAllSkills(getStudentName());
return skills;
}
#RequestMapping(value = "/addskill", method = RequestMethod.PUT)
#ResponseStatus(value = HttpStatus.NO_CONTENT)
public void update(#PathVariable("skill") StudentSkills skills) {
skills.setStudent(studentService.getStudent(getStudentName()));
studentService.addStudentSkill(skills);
}
I want to fetch all the skills saved by using refreshSkill() function, and submit new skills through form. It is not working and i have tried but could not get it to work. How to link form like we can link using #modelAttribute. Or any other way to submit form using ajax. Thank You.
maybe you should follow some Angular JS tutorial or example, such as Angular phone tutorial, and this guide of the notion scope.
There are several problems in your codes :
1, you should define the json object skill in your controller, so that your view can recognize it : $scope.skill={};.
2, as the api of $http.put shows, the syntax should be : put(url, data, [config]);. So you should modify your code to
$http.put('/user/addskill/', $scope.skill).success($scope.refreshSkill());
3, in the server side, you should use the annotation #RequestBody for the StudentSkills parameter, like this :
public void update(#RequestBody StudentSkills skills) {
// your codes ...
}
Because the annotation #PathVariable is for the uri parameter, and when you use http put, the parameter is stored in the request body.
Hope help!

Categories