I have a Razor View which has a section where the user can add new rows for ad-hoc opening/closing times on specific dates. It consists of three controls - a DatePicker, two Select lists and a "delete row" button. Existing saved rows are rendered on page-load through Razor, and any new rows are added via an OnClick event and JavaScript appending largely fixed html to the DOM element. All rows are then saved (or removed as required) on HTTPPost.
I have a new requirement which requires implementation of a much more complicated data-set for these ad-hoc, "user-generated" rows. The HTML for each of these rows is extensive. Is there a more elegant way of injecting Razor within a View on a button click than appending hard-coded HTML in JavaScript?
This depends entirely on your use case, and you did not provide any code in your question, but there's something called Partial View. You can read a basic introduction here.
For your case, I'd do something like this:
Controller
public IActionResult GetNewRow()
{
return PartialView("_NewRow");
}
View
<button id="btnAddRow" class="btn btn-primary">Add new row</button>
<script type="application/javascript">
$(function() {
$("#btnAddRow").on("click", function () {
$.get("/GetNewRow", function success(data) {
$("#WHEREVERYOUAREADDINGROWS").append(data);
});
});
});
</script>
PartialView (_NewRow)
<tr>
<td>Add whatever you need here</td>
<tr>
Note: I didn't try this so the AJAX syntax might be a little off.
Related
I want to add a PartialView multiple times by pressing a button.
<div id="FilterRows">
#{Html.RenderAction("_FilterRow");}
</div>
<button id="newRow" type="button"
class="btn btn-sm btn-default"
style="width: 50px">+</button>
This piece of code works properly. But now i want to append the div FilterRows with another PartialView of _FilterRow at clicking on the button.
This is how it looks today:
Something like:
$(document).ready(function() {
$("#newRow").click(function() {
$("#Exec").append("<br>", #{Html.RenderAction("_FilterRow");} {
});
});
});
Is unfortunately not working. Any Ideas?
If you add an action which returns the partial rendered as a partial (ie. return PartialView("myView", model); then you can load using jQuery:
# Create a new element to contain...
var el = $('<div></div>');
$('#parent').append(el);
# ...the new content
el.load('#Url.Action("action", "controller"');
(This means running the JS in the razor view to get the correct URL generation. If most of the JS is in its own file, pass the URL from a little JS in the Razor file just for things like URLs.)
As long as your script is in the page (and not in an external .js file) you can use Razor inside js (although feedback directly from MicroSoft indicates that this is "unexpected", it works fine).
Have a look at the rendered html to see what's wrong.
In this case you need quotes (") around the render action:
$("#FilterRows").append("#{Html.RenderAction("_FilterRow");}");
This assumes a number of potential issues:
the 'RenderAction' can't have any newlines in the output
the 'RenderAction' can't have any quotes in the output (either use ' on the append and " inside the render or the other-way-around)
the action to be rendered cannot have any row-specific parameters (which appears to be ok in this case to add a new blank row)
the script must be in a .cshtml file (though you can get around this by setting a global/namespace'd variable in the .cshtml and have the actual code in a .js file)
you need to use the correct combination of #{}/#() and render/tostring
You might be better off with #Html.RenderPartial if you just want to render some html and don't need an action.
An alternative, perhaps more friendly, mechanism would be to have the blank-row already on the page (perhaps hidden) and use .clone().
I have 3 different view(DetailView, CardView, Column) template/html pages to show in single-page. The user can switch between these 3 view.
I want to bind single view at a time in page, if user switch it will remove previous view and bind the new view. I have data in Model for bind the view so, I no need to call service to bind data. I want toggle between these three-view without refresh page and loading data.
Problem is, if bind three view it will conflict with div-id and there are lots of html-code for all view in DOM.
Please suggest me how to toggle between these different view without loading & refreshing page??
<body>
<div ng-include="'detailView.html'" ng-show="detailView"></div>
<div ng-include="'cardView.html'" ng-show="cardView"></div>
<div ng-include="'cardView.html'" ng-show="cardView"></div>
</body>
As i know Angular Apps are SPA (Single Page Application) so if you switch pages by routing its default behavior its the one that you are asking for. Its not reloading/refreshing the page. It remove the previous view and bind the new one.
Check this guide : https://scotch.io/tutorials/single-page-apps-with-angularjs-routing-and-templating
Also try to use $location service to switch routes. It does not reload the page.
$location.path("/your-route").
Angular has routing module. This way you can define a route (page) with it's own URL, HTML template and controller.
configuration example:
YOUR_MODULE.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
You can read more about it in angular's documentation:
https://docs.angularjs.org/tutorial/step_07
For bigger applications I would suggest you to use UI-ROUTER:
https://github.com/angular-ui/ui-router
Anyway, if you're looking for something simple without any routing, you should use NG-IF instead of NG-SHOW.
NG-SHOW just hiding the HTML by css (display none) which means there might be conflicts for elements with the same IDs.
NG-IF will remove the element from the DOM, so there won't be any conflicts.
Good luck!
From what i could understand, when the first time the page loads, you have certain flag up to show that view and corresponding call to a service to bind data to that view.
Next time, the model is updated and a new flag is set, a new view comes into play and a similar service binds data..
Initially set the model all to false and make one true for default.
Toggle through view as:
<body>
<div ng-include="'detailView.html'" ng-if="detailView"></div>
<div ng-include="'cardView.html'" ng-if="cardView"></div>
</body>
Through this, at a particular time only one div is active and id would not conflict.
In the controller:
If($scope.detailView == true){
//Call to service for data..
}
Similarly, when the new model is updated , set all previous to false.
Please update your query to more clarify your objective.
When i click button jquery doesn't work in partial view
here is code
Controller
public PartialViewResult Chat()
return PartialView();
}
Button
<input id="button" type="submit">
Render In HTML
<div id="test">
#{Html.RenderPartial("Chat");}
</div>
Javascript
$('#button').live('click', function () {
$('#test').load('#Url.Action("Chat")');
});
Several possible reasons most likely including:
you didn't include jQuery library at all
you didn't call $('#button').live() in a $(document).ready() statement
jQuery initialisation is done to all matching elements in the document at the time of running. If you are dynamically loading your partial view after the initialisation, new elements matching the filter will not be automatically initialised. You will need to run the jQuery initialisers again after the .load is complete.
This will also double up existing matching elements' events so you need to run them using the container div to restrict the elements that will be affected.
$('#test').find('xxxxx').click(function.....
I have a Razor form with a list/table of items that I'd like to dynamically add items to. You can select the items from a dropdown, click "Add", and the item from the dropdown will be added to the list. I'd then like all of that to be sent via POST when I submit my form and my controller's HttpPost method can handle the input.
Is there a way to dynamically add fields and still be able to accept them as arguments in the HttpPost function?
The first answer is correct in that you can iterate over a form collection to get the values of the dynamically inserted fields within your form element. I just wanted to add that you can utilize some of the neat binding.
The code below accepts a dynamic list of textboxes that were posted against the action. Each text box in this example had the same name as dynamicField. MVC nicely binds these into an array of strings.
Full .NET Fiddle: https://dotnetfiddle.net/5ckOGu
Sample code (snippets for clarity) dynamically adding sample fields
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div id="fields"></div>
<button>Submit</button>
}
<div style="color:blue"><b>Data:</b> #ViewBag.Data</div>
<script type="text/javascript">
$(document).ready(function() {
var $fields = $('#fields');
$('#btnAddField').click(function(e) {
e.preventDefault();
$('<input type="text" name="dynamicField" /><br/>').appendTo($fields);
});
});
</script>
Sample code from the action accepting the dynamic fields in a post.
[HttpPost]
public ActionResult Index(string[] dynamicField)
{
ViewBag.Data = string.Join(",", dynamicField ?? new string[] {});
return View();
}
Screenshot of output
Every combobox/hiddenfield/textbox/... that is included inside the <form> element gets posted on submit. Doesn't really matter if you create them on-fly or have them ready by default. The biggest difference however is that with those created dynamically you can't really utilize that neat binding we're used to. You'll have to perform validation etc. manually as well.
Then you'll have a method like this:
public ActionResult HandleMyPost(FormCollection form)
{
// enumerate through the FormCollection, perform validation etc.
}
FormCollection on MSDN
I have a form to which I want to add extra fields depending on the value of a dropdown list. They would be sets of fields and I was thinking on dynamically changing a div's content with the html from a render partial, which would render a PartialView with the fields I want.
Right now the code for the drop down list is the following
<p>
<label for="CatalogItem.Type"> Type: </label>
<%=Html.DropDownList("CatalogItem.Type",Model.Types, "Choose Type") %>
</p>
<div id = "ExtraInfo">
</div>
And I want to put the extra stuff (fields specialized for the type) in the ExtraInfo div. What would the jQuery code be for this?
Thanks!
#Tony has the right approach but instead of putting your RenderPartial html right into the ".html("add html code inside div here")" you may want to do an ajax call. That way the user isn't downloading a bunch of html he/she may not even see.
something like so:
if ( myval == "someValue")
{
$("#ExtraInfo").load("/dynamic-stuff/1")
}
else if ( myval == "someOtherValue")
{
$("#ExtraInfo").load("/dynamic-stuff/2")
}
This also assumes you have a route set up to handle a url like "/dynamic-stuff/2" and responds with the correct partial view.
First add a css class selector to your dropdown, lets call it 'mydropdown' for now
use something like this:
<script language=”javascript” type=”text/javascript” >
function addtoDiv()
{
$(document).ready(function() {
var myval=$(”#mydropdown”).val(); // get value of dropdown
if ( myval == "somevalue") // check myval value
{
$("#ExtraInfo").html("add html code inside div here"); // add code based on value
}
}}
</script>
Do you need to dynamically add fields? You can add fields with JQuery by doing:
$("").attr("id", "test").addClass("FormLabel").appendTo("#parentElement");
$("").attr("id", "testinput").attr("type", "text").appendTo("#parentElement");
In this way, you can create the fields programmatically.
As an alternative, you can create a JQuery partial view. Create an action method that returns an instance of this partial view, and call that action method using
$.get("/<controller>/<actiontoreturnpartialview>", function(data) {
$("#ExtraInfo").html(data);
});
It makes it easier because then you can rely on server-side logic to render the UI, though I tend to use the client-side approach.
Alternatively, you can create your own HTML helper to do this all, but that would be a lot of work.
HTH.