I'm working on Asp.net Mvc news website like (yahoo, BBC ...).
I have loads of divs that contains the feed title,text and image.What I want to achieve is to make these divs that contains these 3 elements clickable no matter where I clicked (title,text or feed image)and to post the value of the feed ID to my controller method.
I've done this already like this:
In my feed table I have : FeedID-FeedText-FeedPath
View:
#foreach (Feeds item in Model.FeedViewModel)
{
<div class="col-4">
#using (Html.BeginForm("goToFeed", "Home"))
{
<h3>#item.title</h3>>
<button type ="submit" name="FeedID" value="#item.FeedID"
style="background:none; border:none" href="#">#item.FeedText</button>
<img src="#Url.Content(#item.FeedPath)">
}
</div>
}
And in my controller I'm taking the "FeedID"
Controller:
[HttpPost]
public ActionResult goToFeed(int FeedID)
{
//some code here
}
I guess there should be a way to post the FeedID inside this div without making it a button.
I've checked these posts already but none of them helped me.
Form submit by click on a div element without JS
submiting form on div click with js
Thanks for any help...
You should not use a POST request to read data. The correct HTTP verb in this case would be GET. POST should mainly be used to create new entries. See Using HTTP Methods for RESTful Services.
This has not only academic reasons. If you use POST, and your users use the backwards/forwards buttons of the browser to navigate, they would see "Are you sure you want to resubmit the form?" messages.
To use GET, your CSHTML could look like this. Use CSS marker classes js-feed and js-feedId so you can later access these elements using jQuery.
#foreach (Feeds item in Model.FeedViewModel) {
<div class="col-4 js-feed">
<h3>#item.title</h3>>
<span>#item.FeedText</span>
#Html.HiddenFor(m => item.FeedID, new { #class = "js-feedId" })
</div>
}
The URL to the GET action is configured in the JS part. Extract the FeedId from the clicked div, replace the placeholder in the configured URL with this FeedId, and then redirect to this action by setting window.location.href, which will reload the page.
If you do not want to reload the entire page, use $.ajax instead.
<script type="text/javascript">
$(document).ready(function() {
var getUrl = '#Url.Action("goToFeed", "Home", new { FeedID = "To_Be_Replaced_By_JS" })';
$('.js-feed').on('click', function() {
var feedId = $('.js-feedId', $(this)).val(); // search only inside clicked element
var feedUrl = getUrl.replace('To_Be_Replaced_By_JS', feedId);
window.location.href = feedUrl;
});
});
</script>
The target controller action should be attributed with [HttpGet].
[HttpGet]
public ActionResult goToFeed(int FeedID) {
//some code here
}
Change this:
#foreach (Feeds item in Model.FeedViewModel)
{
<div class="col-4">
#using (Html.BeginForm("goToFeed", "Home"))
{
<h3>#item.title</h3>>
<button type ="submit" name="FeedID" value="#item.FeedID"
style="background:none; border:none" href="#">#item.FeedText</button>
<img src="#Url.Content(#item.FeedPath)">
}
</div>
}
To this:
#foreach (Feeds item in Model.FeedViewModel)
{
<div class="feed col-4">
#using (Html.BeginForm("goToFeed", "Home"))
{
#Html.HiddenFor(m => item.FeedID)
<h3>#item.title</h3>>
<button type ="submit" name="FeedID" value="#item.FeedID"
style="background:none; border:none" href="#">#item.FeedText</button>
<img src="#Url.Content(#item.FeedPath)">
}
</div>
}
Then add this to your page:
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script type="text/javascript">
$(function() {
$('.feed').click(function() {
return $(this).closest("form").submit();
});
});
</script>
Having a field is required when posting a razor form to the server so having the FieldID hidden will allow this to be sent. Having a div surrounding the area adding the onclick attribute with a submit function to post the above form document.forms[0].submit() can also be used.
#foreach (Feeds item in Model.FeedViewModel)
{
<div class="col-4">
#using (Html.BeginForm("goToFeed", "Home"))
{
<div onclick="this.parentNode.submit()">
#Html.HiddenFor(m => item.FeedID)
<h3>#item.title</h3>>
<button type ="submit" name="FeedID" value="#item.FeedID"
style="background:none; border:none" href="#">#item.FeedText</button>
<img src="#Url.Content(#item.FeedPath)">
</div>
}
</div>
}
Related
I'm learning laravel, and now i trying to delete object without form.
i want to use js to detect when user click delete's button and return notify to controller. Then controller with delete object with id has returned from JS file.
This is blade file
#extends ('layouts.master')
#section ('head.title')
Blog
#stop
#section ('body.content')
<div class="container">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
</div>
</div>
<form class="form-show">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<h2> {{ $article->title}} </h2>
<p> {{ $article->content}} </p>
</div>
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
Update
<button id="delete-button" type="submit" class="btn btn-primary">Delete</button>
</div>
</div>
</div>
</form>
</div>
<script src="{{ asset('/js/jshow.js') }}"></script>
#stop
And this is controller file
class ArticlesController extends Controller
{
protected $articleModel;
public function __construct(Article $article){
$this->articleModel = $article;
}
public function index(){
$articles = $this->articleModel->getListArticles();
// $articles = Article::paginate(10);
return view('articles.index',compact('articles'));
}
public function show($id){
// $article = Article::find($id);
$article = $this->articleModel->getArticleWithID($id);
return view('articles.show',compact('article'));
}
public function delete($id){
$this->articleModel->deleteArticle($id);
return redirect()->route('articles.index');
}
}
And here is JS file
var deleteButton = document.getElementById("delete-button");
var idPost = document.getElementById("")
deleteButton.onclick = function() {
alert('Click to delete');
return false;
}
You need to use $.ajax from the jQuery JS library.
Try to understand and to do something, then come back if you any have difficulties.
Like Jerodev said, AJAX calls can be done without jQuery, but I find the jQuery method more understandable. Check here to read more about AJAX using plain JavaScript.
AJAX Request in Jquery is that for you ...
first learn how AJAX Work to request server .
use jquery to easy that for you .
remake delete function to make it more able with AJAX Request to just delete the object and response data .
public function delete(Request $req)
{
$this->articleModel->deleteArticle($id);
return response()->json(['msg' => 'some Msg help]);
}
make route for this function .
then make the ajax request to get this route and delete the object and return the msg you make .
but you must first Learn AJAX .
I created a two panel one for the user's options and the second panel is the transition of the panel. As you can see below I have a group of buttons every-time the user click the buttons the left panel will changed it's content every-time it clicks. But it won't work if I click on the buttons.
I used empty() so it will be empty first the panel-body on my left container after that I will append in the panel-body section
Master page below.
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "{{ URL::asset('css/bootstrap.min.css') }}">
<script type = "text/javascript" src = "{{ URL::asset('js/jquery.js') }}"></script>
<script>
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is subjects");
});
});
</script>
</head>
<body>
#include ('layouts.navigation.user')
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
<div class = "panel panel-default">
<div class = "panel-body" style = "height: 300px">
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "curriculum"> Curriculum
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "subjects"> Subjects
</label><br>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class = "panel panel-default">
<div class = "panel-body" id = "rightContainer" style = "height: 300px; overflow-y: scroll;">
//RIGHT CONTAINER
</div>
</div>
</div>
</div>
</div>
OPTIONS:
subjectsOption
curriculumOption
subjectsOption.blade.php
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "subjectList"> Subject List
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "createSubjects"> Create Subjects
</label><br>
<div>
curriculumOption.blade.php
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "curriculumList"> Curriculum List
</label><br>
<label class = "btn btn-primary btn-lg">
<input type = "checkbox" id = "createCurriculum"> Create Curriculum
</label><br>
</div>
I don't understand why you out checkbox in label. I have just remove the checkbox and add id to labels.
Add insert php file data using html()function.
<!DOCTYPE html>
<html>
<head>
<link rel = "stylesheet" href = "{{ URL::asset('css/bootstrap.min.css') }}">
<script type = "text/javascript" src = "{{ URL::asset('js/jquery.js') }}"></script>
<script>
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
//$("#rightContainer").empty();
$("#rightContainer").html(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
//$("#rightContainer").empty();
$("#rightContainer").html(data);
alert("This is subjects");
});
});
</script>
</head>
<body>
#include ('layouts.navigation.user')
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
<div class = "panel panel-default">
<div class = "panel-body" style = "height: 300px">
<div class = "btn-group" data-toggle = "buttons">
<label class = "btn btn-primary btn-lg" id = "curriculum">
Curriculum
</label><br>
<label class = "btn btn-primary btn-lg" id = "subjects">
Subjects
</label><br>
</div>
</div>
</div>
</div>
<div class="col-lg-6">
<div class = "panel panel-default">
<div class = "panel-body" id = "rightContainer" style = "height: 300px; overflow-y: scroll;">
//RIGHT CONTAINER
</div>
</div>
</div>
</div>
</div>
Laravel Blade Template, or PHP file inside the /resources/views inside Laravel framework is not accessible using URL directly, to be precise, everything under /resources folder and even all other folders except /public, are not accessible. Only public folder can be accessed directly by using URL in laravel framework. You must notice that the view inside resources folder can only be returned after come from route -> controller -> view to be simple.
Thus, this part of your code
$(document).on("click", "#curriculum", function ()
{
$.get("curriculumOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
$(document).on("click", "#subjects", function ()
{
$.get("subjectsOption.blade.php", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is subjects");
});
});
is trying to access your server in certain URL. lets take example your domain is test.laravel.dev and you are in root of your domain (in your browser you can see http://test.laravel.dev), and you run these script there. It means that you are trying to do AJAX request to url http://test.laravel.dev/curriculumOption.blade.php and http://test.laravel.dev/subjectOption.blade.php. What will happens? this will try to find route in your routes.php file, looking for "/curriculumOption.blade.php" or "/subjectOption.blade.php" which i am sure it's not exists there. what you can do is, if you still need the blade template to be processed before returning as AJAX response, you can make it like this:
routes.php
Route::get("/curriculumOption","CurriculumOptionController#show");
CurriculumOptionController.php
public function show()
{
//do your things here
return view("curriculumOption");
}
with the curriculumOption.blade.php is under /resources/views folder, and change your ajax request to:
$(document).on("click", "#curriculum", function ()
{
$.get("/curriculumOption", function (data)
{
$("#rightContainer").empty();
$("#rightContainer").append(data);
alert("This is curriculum");
});
});
This will work, please try and ask if have any other problem.
Explanation #1
Due to some security reason and also as a feature for laravel, most of the folders except public cannot be accessed without PHP preprocessor. When you are making a request in browser, the HTTP request is being sent to your browser to the server. in this case, if you make get request, you dont pass any other additional form parameters to server. Server read the request URL from your browser and then there are some server configuration in how are they going to pass the parameter to PHP preprocessor. These configuration is set in .htaccess file for apache HTTP server, nginx configuration for NGINX, and web.config for IIS server. You can notice that the .htaccess file is included in your /public folder of laravel project and the /public folder is the default for your domain, lets say your domain is test.laravel.dev, then test.laravel.dev is equal to /public and test.laravel.dev/index.php is refering to /public/index.php file. The rest that can be put in /public usually are css, javascript, and image files. Templates, Controller, Routes, etc are not accessible from URL. They are being managed by the framework. /resource folder is not accessible for security reason also. The only way is to access it from route or controller. If you dont define what to do with a certain URI, laravel framework will not give a proper response which is most likely erorr. Your /management/curriculumOption.blade.php can't be accessed simply because you dont have a route with
Route::get("/management/curriculumOption.blade.php"/, .....)
even though i dont think you can put .blade.php in the parameters also, but worth to try. There are only 2 options(need citation) to access certain URL to be responded in Laravel:
Define it in routes.php
put it in public folder
I used to use this in Web Form development through the id and name of the input radio button, but can't seem to get it in MVC5, could someone point out what I'm doing wrong?
On a radio button (part of the model) selection, depending which button, I want another text box to appear (within a div).
View:
<div class="ui-grid-solo">
<div class="ui-grid-solo">
<div class="ui-block-a">
<p>AS Number Type</p>
<span>
#Html.RadioButtonFor(model => model.NumberType, "Odd", true)Odd
#Html.RadioButtonFor(model => model.NumberType, "Even", false)Even
</span>
</div>
</div>
#if (Model.NumberType == true)
{
<div id="OddOrEven">
<div class="ui-grid-solo">
<div class="ui-block-a">
<span>
#Html.EditorFor(m => m.Reason)
</span>
</div>
</div>
</div>
}
JavaScript:
#section Scripts
{
<script type="text/javascript" src="~/Scripts/maintainscroll.jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("input[Value='Odd']").click(function () {
var test = $(this).val();
$("#OddOrEven").show();
});
});
</script>
}
I would do it like this:
#Html.RadioButtonFor(model => model.NumberType, "Odd", true)Odd
#Html.RadioButtonFor(model => model.NumberType, "Even", false)Even
<div id="OddOrEven">
<div class="ui-grid-solo">
<div class="ui-block-a">
<span>
#Html.EditorFor(m => m.Reason)
</span>
</div>
</div>
</div>
<script>
$("#OddOrEven").hide();
$("input[name='NumberType']").on("change", function () {
if ($(this).val() == "Odd") {
$("#OddOrEven").show();
}
}):
</script>
Basically, grab the change event of your radio button group by the input's name, rather than the value. The issue with using the value is that if you have multiple radio button groups on the same view, and they each have the same value pairs (ie: true/false), then your view would not know which radio group to select. Using name is the proper way to go.
Remove the #if surrounding the div, set the div css class to hidden on page load, then your button will work, however clicking off of it will still leave it there, add to the javascript to hide the textbox again.
So remove that #if change your div to <div id="OddOrEven" style="display:none"> and the below within your script:
$(document).ready(function () {
$("input[Value='Odd']").click(function () {
$("#OddOrEven").show();
});
$("input[Value='Even']").click(function () {
$("#OddOrEven").hide();
});
});
In my application I was using simple View the Validation, both client and server side validation, was working fine, but now I have changed to bootstrap modal and PartialView. The problem is that Client Side Validation dosn't work any more and for server side validation when I click submit he redirect me to new page (see picture) instead of showing the error on the current modal pop-up.
Create Controller :
[HttpGet]
public ActionResult Create()
{
ViewBag.CAT_ID = new SelectList(db.CATEGORIE, "CAT_ID", "LIBELLE");
ViewBag.C_GARANT = new SelectList(db.GARANTIE, "C_GARANT", "LIB_ABREGE");
return PartialView("_Create");
}
//
// POST: /Taux/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(TAUX taux)
{
if (ModelState.IsValid)
{
db.TAUX.Add(taux);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CAT_ID = new SelectList(db.CATEGORIE, "CAT_ID", "LIBELLE", taux.CAT_ID);
ViewBag.C_GARANT = new SelectList(db.GARANTIE, "C_GARANT", "LIB_ABREGE", taux.C_GARANT);
return PartialView("_Create", taux);
}
_Create Partial View :
#model pfebs0.Models.TAUX
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="CreateTaux">Add</h3>
</div>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="modal-body">
<div class="form-group">
<div class="form-group">
<label for="Categorie">Categorie : </label>
#Html.DropDownList("CAT_ID", String.Empty)
#Html.ValidationMessageFor(model => model.CAT_ID)
</div>
//Other Form input.
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-default">Submit</button>
</div>
}
</div>
<script>
$("select").addClass("form-control");
$("input").addClass("form-control");
$("label").addClass("control-label");
</script>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval") }
Index View where I puted the modal :
<p>
#Html.ActionLink("Ajouter", "Create", "Taux",
new { id = "btnAdd", #class="btn btn-default"})
</p
<div id="modalDiv" class="modal fade" >
<div class="modal-dialog">
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(function () {
$.ajaxSetup({ cache: false });
$('#btnAdd').click(function () {
$('.modal-dialog').load(this.href, function () {
$('#modalDiv').modal({
backdrop: 'static',
keyboard: true
}, 'show');
});
return false;
});
});
</script> }
So what I have to add or change to Have client validation in my modal and for server validation to be redirected to modal, instead new page like in picture ?
You can rely on the built in bootstrap functionality of the role and data-target attributes. If you define your modal's role as "dialog" and give it an id then you can reference that in a HTML button with a data-target and data-toggle attributes.
You also need to avoid loading your _Create partial from an ajax request. Just load it along with Index using #Html.Partial. It will not appear in your view if the attributes are set correctly.
Here are the steps I did to get it working:
First modify your _Index to load partial view and update your modalDiv to define a role.
<div class="modal fade" id="modalDiv" tabindex="-1" role="dialog" aria-hidden="true">
#Html.Partial("~/{PathToView}/_Create.cshtml", new pfebs0.Models.TAUX())
</div>
Now instead of using #HtmlActionLink and JavaScript to load dialog, create a button as follows. Make sure to remove the JS click event code.
<button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#modalDiv">Ajouter</button>
Now bootstrap will handle showing and hiding dialog automatically with the defined role and data attributes and MVC validation will appear correctly. You can leave your controller code as-is.
I have the following:
_ImageGalleryPartial
#if (Model != null)
{
foreach (var item in Model)
{
#Html.Partial("_ImageItem", item);
}
}
_ImageItemPartial
#model WebsiteEngine.Models.PortfolioImage
#{
string url = VirtualPathUtility.ToAbsolute(String.Format("~/{0}", Html.DisplayFor(m => m.FileName)));
}
#using (Html.BeginForm("DeleteImage", "Portfolio", FormMethod.Post, new { #class = "deleteImageForm" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true);
#Html.HiddenFor(m => m.Name)
#Html.HiddenFor(m => m.FileName)
#Html.HiddenFor(m => m.Order)
#Html.HiddenFor(m => m.PortfolioID)
#Html.HiddenFor(m => m.PortfolioImageID)
<div class="span3">
<div class="item">
<a class="fancybox-button" data-rel="fancybox-button" title="Photo" href="#url">
<div class="zoom">
<img src="#url" alt="Photo" />
<div class="zoom-icon"></div>
</div>
</a>
<div class="details">
<i class="icon-remove"></i>
</div>
</div>
</div>
}
When I inspect the page elements using Chrome dev tools, the first element is missing the surrounding form. If I inspect the page source (using right) click then the form is there. This lead me to believe some JS was removing the form so I disabled JS but it was still missing.
If change _ImageGalleryPartial so it's like this (notice the addition of an empty model):
#if (Model != null)
{
#Html.Partial("_ImageItem", new WebsiteEngine.Models.PortfolioImage());
foreach (var item in Model)
{
#Html.Partial("_ImageItem", item);
}
}
Then all the "correct" elements get a form but again, this first item doesn't.
I'm still inclined to think this is a JS issue but I'm a little stumped as disabling JS doesn't fix it. Is this some off behaviour with MVC?
Just to note, I have simplified my layout above, I do actually have one or 2 nested forms but assume that's Ok as everything else is Ok, it's just this first partial that's broken.
Any ideas?
Html forms can't be nested.
Chrome will ignore illegal tags, thus they are not showing.
You can read this post for further information.