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().
Related
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.
This is the MVC 5 razor view code: ForestView.cshtml
#model Forest.Tree
#{
var resultHtml = string.Empty;
}
<div id="divTreeSearch>
#(Html.Kendo().PanelBar().
Name("panelbar")
.Items(panelbar =>
{panelbar.Add()
.Content(#<text>#Html.Partial("_TreeSearch", Model, ViewData)</text>);}))
</div>
<div id="divTreeSearchResult">
#if(Model.TreeResultObj != null)
{
resultHtml = Html.ContentFromPartial("_TreeReport", Model.TreeResultObj);
#Html.Raw(resultHtml); -- Not working
#Html.Raw(HttpUtility.HtmlDecode(resultHtml)); -- Not Working
Html.Raw(resultHtml); -- Not working
Html.Raw(HttpUtility.HtmlDecode(resultHtml)); -- Not Working
Model.resultStringSaved = resultHtml;
#Html.DisplayText("resultStringSaved"); -- Not Working
#Html.Raw("<text>Test</text>") -- Even this is not working
}
#Html.Raw(Model.resultStringSaved) -- Not Working
#Html.Raw(HttpUtility.HtmlDecode(Model.resultStringSaved)) -- Not Working
#Html.DisplayText("resultStringSaved") -- Not Working
#Html.Raw("<text>Test</text>") -- This is Working
</div>
ForestView.cshtml - #model Forest.Tree
_TreeSearch.cshtml - #model Forest.Tree
_TreeReport.cshtml - #model Forest.SearchData.Results
The projerty TreeResultObj in the model Forest.Tree is of type Forest.SearchData.Results
The ForestView.cshtml is the main view which loads initially and displays the search inputs from the _TreeSearch partial
When search criteria entered and a 'search' button is clicked (all this is from the _TreeSearch) - a ajax call is make and the TreeSearch(id tree) action is called
The action again returns the main 'ForestView' - however now the model property 'TreeResultObj' is populated. so the code within the 'if conditon' in the 'ForestView' executed and calls another partial to get the content back as HTML string, which is saved in the 'resultHtml' variable
At this point I can see the Html Sting like "<Text>blah blah blah</text>"
However trying to display the HTML string below the search panel in the main 'ForestView' is not working - I have tried almost every possible way.
Any text within the if condition is not rendered - it is an ajax call so there is no page refresh - I can see the HTML string value and also save it as a Model property but cannot get to display it in the main view.
Any help would be much appreciated. Thanks in advance.
At that point, you are just invoking a method and ignoring the result. Try:
#: #Html.Raw(resultHtml)
The #: switches to output mode. Note: if you had used something that was clearly markup, it would have switched automatically. For example:
<div>#Html.Raw(resultHtml)</div>
I was also facing the same issue but I could make it to working. I wanted to open a div start and conditionally end it within a for loop.
Put any dummy HTML element before the #Html.Raw
<div id="divTreeSearchResult">
#if(Model.TreeResultObj != null)
{
resultHtml = Html.ContentFromPartial("_TreeReport", Model.TreeResultObj);
<span>dummySpan</span>
#Html.Raw(resultHtml);
#Html.Raw(HttpUtility.HtmlDecode(resultHtml));
#Html.Raw(resultHtml);
#Html.Raw(HttpUtility.HtmlDecode(resultHtml));
Model.resultStringSaved = resultHtml;
#Html.DisplayText("resultStringSaved");
#Html.Raw("<text>Test</text>")
}
#Html.Raw(Model.resultStringSaved)
#Html.Raw(HttpUtility.HtmlDecode(Model.resultStringSaved))
#Html.DisplayText("resultStringSaved")
#Html.Raw("<text>Test</text>")
</div>
After you place a dummy html element there all the below #Html.Raw will work
Happy Coding
Tarak
1 - And the content from render should be violating HTML syntax and Razor normally doesn't render wrong HTML content.
2 - Enclose the HTML.Raw(resultHtml) into dev.
After zillions of tests in a full-day:
Change use of:
#Html.Raw(Html.DisplayFor(modelItem => item.Mensagem))
by:
#Html.Raw(Html.DisplayTextFor(modelItem => item.Mensagem))
You will get the rendered HTML withou any <>!!!
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 partial that defines an Ajax.BeginForm. The model returned has a property for ReportLink created on the server resource that returns a Url to a PartialView.
On the Ajax,BeginForm.OnSuccessFunction I am attempting to return and load html content with $("reportContent").load(AJAXRESULT.RenderLink)
However, I get into an infinite loop somewhere.
Edited to add moving parts:
#model xxxx.Reports.Models.Reports.BaseReportModel
#{Layout = null;}
<div id="reportBase" class="k-content">
<div id="reportControl" >
#using (Ajax.BeginForm(
Model.PostAction,
Model.PostController,
null,
new AjaxOptions() { OnSuccess = "editPostSuccess", OnFailure = "editPostFailure" },
new { id = "reportBase_frmViewer", name = "reportBase_frmViewer" }))
{
#Html.AntiForgeryToken()
#RenderSection("reportParams", required: false)
if (#Model.AllowRefresh){
<input type="button" id="btnRefresh" value="refresh" />
}
if (#Model.AllowExportToPDF){
<input type="button" id="btnPDF" value="PDF" />
}
if (#Model.AllowExportToExcel){
<input type="button" id="btnExcel" value="XLS" />
}
#Html.HiddenFor(p => p.AllowExportToExcel)
#Html.HiddenFor(p => p.AllowExportToPDF)
#Html.HiddenFor(p => p.AllowRefresh)
#Html.HiddenFor(p => p.AutoStartReport)
}
</div>
</div>
<div id="wait"></div>
<div id="reportContent"></div>
//The
<script type="text/javascript">
function editPostSuccess(ajaxContext) {
showWaitIndicator(false);
$('#reportContent').load(ajaxContext.RenderLink**,<--This is a link to an asction that calls renderPartial on the controller** function () {
$("#reportContent").show();
});
}
function editPostFailure(ajaxContext) {
showWaitIndicator(false);
var response = JSON.parse(ajaxContext.responseText);
var errorMessage = response.Message;
$('#reportContent').html('#Resources.labels.lblServerErrorsOnForm' + " " + errorMessage);
$("#reportContent").show();
alert("FAILURE:"+response.Message);
}
Update: I am no longer sure that browser is locking up. The content is 3.15 MB. I think the raw html is very verbose and takes that long to render in the browser. Here is the execution sequence:
LoadPartial(ReportModel) - This has an Ajax.BeginForm() that returns report meta data and has a refresh button. When the refresh button is clicked. I call a js function that loads a div using div.load(ReportModel.RenderLink), which is a url to get the content as html from the controller.
The ReportModel.RenderLink points to a controller method that returns an html report based on model params sent to the controller. The result is a PartialView("ReportContentPartial",string) where string is the html fragment.
For testing the ReportContentPartial just dumps #Model into a div as #Html.Raw(Model) and this is where the browser locks up. I thought it was in an infinite loop but it is just taking way to long to render the html.
The part I do not understand is when I use #Html.BeginForm and dump the #Html.Raw(HTML) it is pretty quick. I need to somehow use the same mechanism used in that rendering method. The report html is fetched and returned in less than a second. The problem is when I trace out of #Html.Raw(HTML) the browser locks and takes +15 seconds to render the content.
I will keep plugging at it. I am sure there is a more efficient way to go about it and I probably need to think about ways to break up the reports.
Update 2: This seems to be development environment issue. I am launching IE from VS2012 using the run command. I sense that something is up with the asp.net dev server. When I load the same url in chrome, while debugging in vs, it renders in less than a second.
I solved this. It seems there was an issue with browser definition files that shipped with .net 40. I resorted back to a forms based version of the reporting application that used .aspx pages and postbacks to see why it would render fast and the MVC version was so slow. When using IE 10 it would not render and I found the _dsoPostBacks were not working on the forms version. I then found Scott Hanselman's blog on browsers definition files and applied the hotfix on the test server and now the mvc version in ie is rendering at an acceptable rate. It has something to do with recognizing the browser and downgrading js support. I do not know why that fixed my problem but it did :)
We want to reduce the number of steps it takes for a user to upload a file on our website; so we're using jQuery to open and postback files using the below markup (simplified):
<a onclick="$('#uplRegistrationImage').click();">
Change profile picture
</a>
<!-- Hidden to keep the UI clean -->
<asp:FileUpload ID="uplRegistrationImage"
runat="server"
ClientIDMode="static"
Style="display:none"
onchange="$('#btnSubmitImage').click();" />
<asp:Button runat="server"
ID="btnSubmitImage"
ClientIDMode="static"
Style="display:none"
OnClick="btnSubmitImage_OnClick"
UseSubmitBehavior="False" />
This works absolutely fine in Firefox and Chrome; opening the file dialog when the link is clicked and firing the postback when a file is selected.
However in IE9 after the file upload has loaded and a user has selected a file; insteaed of the OnChange working I get a "SCRIPT5 Access is denied" error. I've tried setting an arbitrary timeout, setting intervals to check if a file is given to no avail.
There are a number of other questions relating to this; however none appear to have a decent answer (One said set the file dialog to be transparent and hover behind a button!)
Has anyone else resolved this? Or is it absolutely necessary that I provide a button for IE users?
For security reasons, what you are trying to do is not possible. It seems to be the IE9 will not let you submit a form in this way unless it was an actual mouse click on the File Upload control that triggers it.
For arguments sake, I was able to use your code to do the submit in the change handler, but it worked only when I clicked the Browse button myself. I even set up polling in the $(document).ready method for a variable set by the change handler that indicates a submission should be triggered - this didn't work either.
The solutions to this problem appear to be:
Styling the control in such a way that it sits behind a button. You mentioned this in your question, but the answer provided by Romas here In JavaScript can I make a "click" event fire programmatically for a file input element? does in fact work (I tried in IE9, Chrome v23 and FF v15).
Using a Flash-based approach (GMail does this). I tried out the Uploadify demo and it seems to work quite nicely.
Styling a File Upload:
http://www.quirksmode.org/dom/inputfile.html
http://www.shauninman.com/archive/2007/09/10/styling_file_inputs_with_css_and_the_dom
References:
jQuery : simulating a click on a <input type="file" /> doesn't work in Firefox?
IE9 file input triggering using Javascript
getting access is denied error on IE8
Hey this solution works.
for download we should be using MSBLOB
$scope.getSingleInvoicePDF = function(invoiceNumberEntity) {
var fileName = invoiceNumberEntity + ".pdf";
var pdfDownload = document.createElement("a");
document.body.appendChild(pdfDownload);
AngularWebService.getFileWithSuffix("ezbillpdfget",invoiceNumberEntity,"pdf" ).then(function(returnedJSON) {
var fileBlob = new Blob([returnedJSON.data], {type: 'application/pdf'});
if (navigator.appVersion.toString().indexOf('.NET') > 0) { // for IE browser
window.navigator.msSaveBlob(fileBlob, fileName);
} else { // for other browsers
var fileURL = window.URL.createObjectURL(fileBlob);
pdfDownload.href = fileURL;
pdfDownload.download = fileName;
pdfDownload.click();
}
});
};
This solution looks like it might work. You'll have to wrap it in a <form> and get it to post in the jquery change handler, and probably handle it in form_load using the __eventtarget or and iframe or whatever it is that web forms uses, but it allows you to select a file, and by submitting the form, it should send it. I can't test it however, since I don't have an environment set up at home.
http://jsfiddle.net/axpLc/1/
<a onclick="$('#inputFile').click();">
Change profile picture
</a>
<div id='divHide'>
<input id='inputFile' type='file' />
</div>
$('#inputFile').change(function() { alert('ran'); });
#divHide { display:none; }
Well, like SLC stated you should utilize the <Form> tag.
First you should indicate the amount of files; which should be determined by your input fields. The second step will be to stack them into an array.
<input type="file" class="upload" name="fileX[]"/>
Then create a loop; by looping it will automatically be determined based on the input field it's currently on.
$("input[#type=file]:nth(" + n +")")
Then you'll notice that each file chosen; will replace the input name to the file-name. That should be a very, very basic way to submit multiple files through jQuery.
If you'd like a single item:
$("input[#type=file]").change(function(){
doIt(this, fileMax);
});
That should create a Div where the maximum file found; and attaches to the onEvent. The correlating code above would need these also:
var fileMax = 3;
<input type="file" class="upload" name="fileX[]" />
This should navigate the DOM parent tree; then create the fields respectively. That is one way; the other way is the one you see above with SLC. There are quite a few ways to do it; it's just how much of jQuery do you want manipulating it?
Hopefully that helps; sorry if I misunderstood your question.