Pass list from cshtml view to jquery function - c#

Im trying to pass List that is generated from the following function;
public List<long> GetIDs()
{
var ids = new List<long>();
foreach(var s in student)
{
ids.Add(s.ID);
}
return ids;
}
and passing the list through the razor view and access the list in the jquery.
Following is the CSHTML code :
<a href="#" class="color-blue" data-studentids = "#schoolLicense.GetIDs()" onclick="sendWelcomeEmail(this)">
and this is the jquery code where I want to access the list and do actions from the ids I get ;
function sendWelcomeEmail(elem) {
$.each($(elem).attr("data-studentids"), function (index, value) {
alert(index + ": " + value);
});
}
But I'm not getting the Ids from the list instead of that I'm getting error as
TypeError: invalid 'in' operand obj
var length = !!obj && "length" in obj && obj.length,
Can anyone please let me know where Im going wrong?

Your problem is because by outputting the List<string> returned from your GetIDs method you're just coercing it to a string. Therefore your output is:
<a href="#" data-studentids="System.Collections.Generic.List`1[System.Int64]" ...
To fix this you can Join() the data together and then split() it back in to an array in your JS. Try this:
public List<long> GetIDs()
{
return student.Select(s => s.ID).ToList();
}
<a href="#" class="color-blue" data-studentids="#String.Join(",", schoolLicense.GetIDs())">
$('.colour-blue').click(function(e) {
e.preventDefault();
$(this).data('studentids').split(',').forEach(v, i) {
console.log(i + ": " + v);
});
});
Note the simplified use of LINQ in the GetIDs method, and the use of the unobtrusive event handler in the JS.
You can amend the .colour-blue selector in the jQuery object to better match your needs. I simply used it in this example as it was the only relevant attribute on the element.

Related

C# - Jquery : Pass regular params and list<KeyPairValue<string, string>> with $.post from view to controller

I try to pass 'regular' parameters type from an ajax call ($.post) from a view to a controller which is supposed to receive those parameters plus a List>.
I need this List cause those parameters will be different from model.types, and the method in the controller dispatch all params in a switch case to private methods.
I tried several jquery objects builds, JSON.stringify, the array with indexes in the string (I know I can't name columns explicitly... part of my question) which always ends in the List> to null in the backend method.
The 'params' are visible in xhr debug, but the parameter _options is always null (ref controller method).
Here is my vars and my ajax call :
function initDocumentsPreviewsActions() {
$('.documents-list-preview-action').on('click', function () {
if (xhrPreviewLoad != undefined)
xhrPreviewLoad.abort();
$('#documents-preview').html('<div class="general-form-message-loader"></div>');
documentCurrentIndex = $(this).data('btnindex');
setDatatableRowActive();
var documentType = $(this).data('documenttype');
var adherentRessourceId = $(this).data('adherentressourceid');
var annee = $(this).data('annee');
var echeancier = $(this).data('echeancier');
var destinataireid = $(this).data('destinataireid');
var destinatairetypeid = $(this).data('destinatairetypeid');
var emetteurid = $(this).data('emetteurid');
var emetteurmandatid = $(this).data('emetteurmandatid');
var trimestres = $(this).data('trimestres');
var params = [
{ '_annee': '' + annee + '', '_echeancier': '' + echeancier + '', '_trimestres': '' + trimestres + '' }
];
xhrPreviewLoad = $.ajax({
url: '/Documents/PreviewDocumentSingle',
data: {
_documentType: documentType,
_adherentRessourceId: adherentRessourceId,
_annee: annee,
_destinataireId: destinataireid,
_destinataireType: destinatairetypeid,
_emetteurId: emetteurid,
_emetteurMandatId: emetteurmandatid,
_echeancier: echeancier,
_options: JSON.stringify(params)
},
dataType: 'json',
type: 'POST'
}).done(function (documentPartialView) {
$('#documents-preview').html('<img src="' + documentPartialView.src + '"/>');
xhrPreviewLoad = undefined;
});
});
}
xhd Parameters in Firefox debugger :
_documentType AppelCotisation
_adherentRessourceId 836
_annee 2018
_destinataireId 11
_destinataireType Syndicat
_emetteurId 16289
_emetteurMandatId 5986
_echeancier False
_options [{"_annee":"2018","_echeancier":"False","_trimestres":"undefined"}]
Controller method :
[HttpPost]
public JsonResult PreviewDocumentSingle(string _documentType, int _adherentRessourceId, int _destinataireId, string _destinataireType, int _emetteurId, int _emetteurMandatId, List<KeyValuePair<string, string>> _options)
{
//(_options = null)
//some code
return JsonResult
}
I already have done this a long time ago but I cannot put a hand or my brain on it. I'm sure it's a little thing.
I expect to get ALL my parameters correctly or being suggested to declare another List of a different type in the backend (and how to formalize it in front), or Array... well... any help is good to come.
But I'd really like to keep mus ctor in the backend as it is.
I finally findout myself how to solve this simple problem by changing to a Dictionnaray instead of a List> in my controller's method parameters and build a simple js object like this :
var options = {};
options['_annee'] = annee;
options['_echeancier'] = echeancier;
options['_trimestres'] = trimestres;

Format to return data from C# Web Api to Angular ng-repeat

I would like to return back from my API a list of all the products that were updated by the API. The API is called by some AngularJS code that uses a promise that returns data. In what format should I build a string of Products on the server-side that can be interpreted by Angular on the client-side?
C#
string results = "WidgetA - $12, WidgetB - $22 - ....":
return Request.CreateResponse<string>(HttpStatusCode.OK, results);
HTML
<div ng-repeat="model in data ">
{{model.ProductName + ' ' + model.ProductPrice + ' imported' }}
</div>
Angular
.then(function (data) {
// promise fulfilled
if (data === '') {
alert("No Data Returned");
} else {
// Data is returned
// How to get it in model that can be iterated over
}
}
Ideally I would like to end up with a list a Products and Prices that were updated.
The problem is that you're returning a string. Which is just, well, a string. But you want to return an array of something.
So return an array of something:
var results = new List<Product>
{
new Product("WidgetA", 12.0),
new Product("WidgetB", 22.0)
};
return Request.CreateResponse<IEnumerable<Product>>(HttpStatusCode.OK, results);
(Assuming you've created a Product class, of course. Construct that however you like.)
Then client-side:
.then(function (data) {
// promise fulfilled
if (data.length === 0) {
alert("No Data Returned");
} else {
// "data" is an array of products here
}
}
Structured and defined models are generally easier to work with than string blobs that would need to be parsed and interpreted anywhere you want to use them.

razor throws an exception while rendering

I have a razor statement:
#{
var renderColumn = new Action<OlapReportColumn>(col =>
{
if (col.IsSpaned)
{
#<th colspan="#col.Columns.Count">#col.Caption</th>;
}
});
}
Here is a code for render html table's header. So while I trying to call view I get an exception (translated from russian) as:
an operator can be used only assignment expression, call, increment, decrement and expectations
Here is a razor generated code part with an error:
var renderColumn = new Action<OlapReportColumn>(col =>
{
if (col.IsSpaned)
{
#line default
#line hidden
item => new System.Web.WebPages.HelperResult(__razor_template_writer => { // ERROR HERE!
BeginContext(__razor_template_writer, "~/Areas/Report/Views/ReportsOlap/ReportTableGenerator.cshtml", 324, 3, true);
Here a part of razor code called renderColumn
<table id="reportGrid">
<thead>
<tr>
#foreach (var h in report.Header)
{
renderColumn(h);
}
</tr>
What I am doing wrong in here?
The Action that you've defined is behaving just like any other method in C#. The line #<th colspan="#col.Columns.Count">#col.Caption</th>; is not simply output to the output stream; instead the compiler is seeing a statement that it doesn't understand resulting in the error:
CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
In order to write the <th colspan="#col.Columns.Count">#col.Caption</th> to the output stream you can use the WriteLiteral method:
var renderColumn = new Action<OlapReportColumn>(col =>
{
WriteLiteral("<th colspan=" + col.Columns.Count + ">" + col.Caption + "</th>");
});
Perhaps more idiomatic than that though would be to use a Func that returns what you'd like to ouptut and then output that at the call site:
var renderColumn = new Func<OlapReportColumn, object>(col =>
{
return Html.Raw("<th colspan=" + col.Columns.Count + ">" + col.Caption + "</th>");
});
The call would then need to be changed very slightly to tell razor that you wish to output the results:
#foreach (var h in report.Header)
{
#(renderColumn(h))
}
Going further, there is built-in support for Funcs of this nature as described in this blog by Phil Haack. Using this method your call stays the same as the call just above but the Func becomes:
Func<OlapReportColumn, object> renderColumn2
= #<th colspan="#item.Columns.Count">#item.Caption</th>;
From Phil Haack's blog
Note that the delegate that’s generated is a Func<T, HelperResult>. Also, the #item parameter is a special magic parameter.
Try changing your HTML table header code from this :
#<th colspan="#col.Columns.Count">#col.Caption</th>;
to this :
#:<th colspan="#col.Columns.Count">#col.Caption</th>;
Insert that colon : immediately after # delimeter and check if this works.

Iterate over Dictionary with java-script selector

I have a Dictionary in my view, there are
[inputID, tooltip].
Also i have a set of id's of my input elements in this page.
I need to iterate through the dictionary with my elements ids:
#{
Dictionary<string, string> questionMarks =
ViewBag.QuestionMarks as Dictionary<string, string>;
#}
<script type="java-script">
$(document).ready(function () {
var inputs = $('input,select[type!="hidden"]');
$.each(inputs, function(i, val) {
if ($(val).attr('id')) {
var id = $(val).attr('id');
var iter_string = '#questionMarks' + "[" + id + "]";
alert(iter_string); // [1]
alert('#questionMarks["cvc"]'); // here i got tooltip
}
});
</script>
[1] i have System.Collection.Generic.Dictionary`2[System.String, System.String][cvc]
Thanks to Jan Jongboom,
Finally i got that i wanted:
#using System.Web.Script.Serialization
#{
Dictionary<string, string> questionMarks = ViewBag.QuestionMarks as Dictionary<string, string>;
JavaScriptSerializer jss = new JavaScriptSerializer();
#}
<script type="text/javascript">
var questionMarks = #Html.Raw(jss.Serialize((Dictionary<string, string>)ViewBag.QuestionMarks));
$(document).ready(function () {
for ( keyVar in questionMarks ) {
$('#' + keyVar).attr('original-title', questionMarks[keyVar]);
$('#' + keyVar).tipsy({ gravity: 'w' });
}
});
</script>
Do something like
<script>
var questionMarks = #new JavaScriptSerializer().Serialize((Dictionary<string, string>)ViewBag.QuestionMarks) ;
</script>
Now you have a javascript variable called questionMarks that you can iterate over.
No, you can't iterate from the client side code through server variable. You can generate initialization code from JS variable (like JSON) or generate necessary html on the server side. Also you can requests for such data on from jsavascript via ajax request.
Attatching data attributes to the inputs as they are drawn should help you with this one.
Example: http://jsfiddle.net/Krch9/
$(document).ready(function(e) {
var inputs = $("input", "#container");
$.each(inputs, function(i, val) {
var ToolTipText = $(this).data('tooltiptext');
/// Run your tooltip plugin here ...
$("#output").html($("#output").html() + "<br>" + $(this).attr('id') + " : " + ToolTipText);
});
});
Using MVC helpers you can easily add them:
#Html.TextBoxFor(x => x.Field, new { data_tooltiptext = "Blah blah"});
The markup would end up looking something like this:
<input type="text" id="Field" data-tooltiptext="Blah blah">
Edit: Extra help
I.E Loop through your elements
foreach( var question in questionMarks) {
#Html.TextBox(question.Key, new { data_tooltiptext = question.Value} );
}
Then use the javascript example (Youll need to modify it to your needs ...) to run the plugin on the elements
To remove the quotes, use Html.Raw()
var questionMarks = '#Html.Raw(jss.Serialize((Dictionary<string, string>)ViewBag.QuestionMarks))';

returning a list from a mvc view

When I look in my DetailsReport(List<> filteredList) method, it's Count = 0. Is it possible to send a List to your controller or is my code bad?
#Html.ActionLink("Print Results to Report",
"DetailsReport",
new {filteredList = Model} )
Your code is bad. You can't pass a Model as part of the Route like that. You need to serialize your Model and send it as either part of the request payload or in the query string. Try something like this (not sure if my serialization is correct with the Razor syntax as I haven't used it):
#Html.ActionLink("Print Results to Report", "DetailsReport", null, new {#id = "printreport")
$(function() {
$('#printreport').click(function() {
e.preventDefault();
$(this).wrap('<form action="' + $(this).attr('href') + '?' +
$.param(#new JavaScriptSerializer().Serialize(Model)) +
'" style="display: inline" method="GET" />');
$(this).parent('form').submit();
});
});

Categories