get sort direction from jquery bootgrid in C# - javascript

i have setup a jquery bootgrid on a .net mvc web page, it shows me a grid with a few commands,like sorting,search autocomplete,scroll pages. Library is here: http://www.jquery-bootgrid.com/documentation
The grid works well, and i decided to send the commands through ajax to a function behind. The library then sends a list of strings to the function, used to handle the grid:
current 1
rowCount 10
sort[filename] asc
where filename is one of the columns for which i wanna sort. it could be sort[id], sort[name] or whatever i set my column to be.
the values are pretty clear, the ajax sends to the function the current grid page,the number of rows and the sorting direction.
but when i get in the function i can read only the first 2 values:
public ActionResult AjaxRequestData(string current,string rowCount,string sort)
this definition reads the first 2 values from the web page,but cannot read the sort ,because the actual name of the var is sort[filename], it's not an array of strings.if i either declare sort as string or string[],the result is always null.
How should i declare the variables in the action? So far i could read the sort by using formcollection["sort[filename]"],formcollection["sort[id]"] etc but i have a lot of columns and i really dont want to write out a condition for each one of them,is there any other solution to this?

Approch1.
consider you have table with columns "col1, col2, col3, ...".
you can use:
public ActionResult AjaxRequestData(string current,string rowCount,Sort sort){
//sort.col1 == 'asc' (consider sorted by col1 in ascending order)
}
public class Sort
{
public string col1 { get; set; }
public string col2 { get; set; }
public string col3 { get; set; }
//... other columns
}
Approach 2.
You can remove you parameters and parse data manually. (notice i used post here instead of get)
[HttpPost]
public object AjaxRequestData(){
string jsonContent = Request.Content.ReadAsStringAsync().Result;
Dictionary<string, string> keyvalues = new Dictionary<string, string>();
string[] keyvalue_strings = jsonContent.Split('&');
string sort_column = "";
string sort_direction = "";
for (var i = 0; i< keyvalue_strings.Length; i++)
{
var a = keyvalue_strings[i].Split('=');
a[0] = a[0].Replace("%5B", "[").Replace("%5D", "]");
keyvalues.Add(a[0], (a[1]));
if (a[0].Contains("sort"))
{
sort_column = a[0].Replace("sort[", "").Replace("]", "");
sort_direction = a[1];
}
}
//now you have keyvalues, sort_column, sort_direction.
//...
}

Related

How to reload jqGrid with 'setGridParam' key pair values?

I have tried to follow question in stackoverflow, but this doesn't help me in my case.
I have a checkbox on my web-page, which if gets clicked(true) shows, only negative values.
I am trying to send data from my JS file to Controllers with change parameters so the grid with negative values comes up.
But I am not getting any hit on controller while debugging it.
//Check for Negative Option
var negative;
$('#checkbox').click(function(){
{
var selected= $('#txtSelected').val();
var summary=$("#chkSummary").is(":checked");
var negative = $("#checkbox").is(":checked");
var locationIdList=$('#locationId').val()
ReloadGrid(selected, summary, negative, locationIdList);
}
})
Where StatusGridId is the name of my table.
function ReloadGrid(selected,summary,negative,locationId) {
$("#StatusGridId").jqGrid('clearGridData');
//Reload grid trigger
$("#StatusGridId").jqGrid('setGridParam',
{
url: "/Reports/GetStatus?"+"locationIdList="+locationId,
postData:{selected: selected, summary:summary, negative: negative}
}).trigger('reloadGrid');
}
My controller where I am not reciving any hit while debugging:
public JsonResult GetStatus ( string sidx, string sord, int? page, int? rows, string selected, string locationIdList, bool? summary, bool? negative )
{
-----code------
}

Javascript Removing elements from an array based on another array

I am using javascript with knockout.js and I have 2 arrays:
self.timesheets = ko.observableArray();
self.selectedTimesheets = ko.observableArray();
I load the timesheet data like so:
$.ajax({
url: '/api/Invoice/GetPendingTimesheets',
type: 'GET',
success: function (timesheetData) {
self.timesheets(timesheetData);
}
});
Where the timesheets are defined like so:
public class Timesheet
{
public int Id { get; set; }
public DateTime WeekStart { get; set; }
}
The selectedTimesheets array keeps track of which checkboxes have been selected
What I would like to do is remove the elements in self.timesheets that are also in self.selectedtimesheets, and I am having a mental block figuring out how to do this:
I know there should be something like
self.timesheets.remove(function (el) {
// ????
});
But I just can't think of how to do it exactly.
Programmatically, you want to iterate through your self.timesheets array and compare each item's id to the ids in self.selectedtimesheets. If the ids match, you want to remove that item from self.timesheets.
Or push all items from both arrays into one new array and remove duplicates.
But since you're using Knockout, if you run the compareArrays utility function:
var differences = ko.utils.compareArrays(self.timesheets, self.selectedtimesheets);
differences will now be an array of only the different values.

List<T> to Javascript array

I have the following classes defined
public ReportsViewmodel
{
public GeographicData GeographicData { get; set; }
...
}
public class GeographicData
{
public List<ZipcodeData> Regions { get; set; }
...
}
public class ZipcodeData
{
//TupleList is defined as public class TupleList<T1, T2> : List<Tuple<T1, T2>>
public TupleList<double, double> Boundries { get; set; }//Contains list of Lat/Long values for plotting on a map.
}
inside my view, I need to do something like this:
foreach (region in GeographicData.Regions)
foreach (boundry in region.Boundries)
add item1 & item2 to a 2 dimensional Javascript array
In the end, I want my javascript array to look like:
var vmBoundries= [[34.1, -85.4], [34.8, -85.234], [34.347, -85.345], [34.541, -85.434], [34.2341, -85.4]];
I can't figure out how to access the data from my view. I keep running into scope issue. For example, if I try to use a javascript for loop I can't index into my ViewModel lists because the loop variable is undefined when I call #Model.GeographicData.Regions[i]...
So how do I pull the data from my ViewModel into the Javascript array?
Typically you'd:
Transform the data into the format you want
Serialize the transformed data into JSON
Assign a JavaScript variable to the serialized value.
So, something like this:
#{
IEnumerable<double[]> flattened = vm.GeographicData.Regions
.SelectMany(region => region.Boundries
.Select(tpl => new double[] { tpl.Item1, tpl.Item2 }));
string json = new JavaScriptSerializer().Serialize(flattened);
}
<script type="text/javascript">
var arr = #json;
// do something with arr.
</script>
Something like:
var array = (from region in GeographicData.Regions
select from boundry in region.Boundries
select new object[] { boundry.Item1, boundry.Item2 }).ToArray();
This will give you a 2D array that you can then just serialize.
Example: https://dotnetfiddle.net/Y9KOaq
I would use a javascript serializer to make it easier:
using System.Web.Script.Serialization;
And add a helper method to ReportsViewmodel:
public string GetBoundriesJs()
{
var pairs =
from r in GeographicData.Regions
from b in r.Boundries
select new[] { b.Item1, b.Item2 };
return new JavaScriptSerializer().Serialize(pairs);
}
Then you can just call it where you need it in your view:
var vmBoundries = #Model.GetBoundriesJs();

Allow to use to add an item to model asp.net mvc4

The model:
public class oPage
{
public int PageId { get; set; }
public List<oContent> Contents { get; set; }
}
The oContent object have properties: Id and Text.
The view: (Razor)
#for (int i = 0; i <= Model.Agrees.Count; i++)
{
#Html.TextAreaFor(m => Model.Agrees[i].Text)
}
I want to let to user to add another content from the client.
I found some solutions that I don't like:
Write the html markup manually. I don't like it because maybe in one day the rendering's structure will change and my code will not word.
(Like here: http://www.techiesweb.net/asp-net-mvc3-dynamically-added-form-fields-model-binding/)
Get the structure from the server. I don't like this because.. well I'm always prefer not use the server unless I have to.
(Like here: How to add items to MVC model in javascript?)
I'm looking for a better and smarter solution.
The solution a little beat complex but I think that it cover all my points.
The logic is:
Get the html from the razor engine
#Html.TextAreaFor(m => Model.Agrees[i].Text).ToHtmlString()
Than replace the index number with the attributes name and id (It makes more sense than relying on all attribute value)
public static string CreateHelperTemplate(string PlaceholderPerfix, MvcHtmlString mvcHtmlString)
{
string Result = "";
XElement TempNode = XDocument.Parse(mvcHtmlString.ToHtmlString()).Root;
XAttribute AttrId = TempNode.Attribute("id");
AttrId.Value = AttrId.Value.Replace("0", PlaceholderPerfix);
XAttribute AttrName = TempNode.Attribute("name");
AttrName.Value = AttrName.Value.Replace("0", PlaceholderPerfix);
// Clear the content if exist
TempNode.SetValue(string.Empty);
Result = TempNode.ToString();
return Result;
}
The result it something like this:
<textarea class="form-control" cols="20" id="Perfix_$__Text" name="Agrees[$].Text" rows="2"></textarea>
Then, in javascript, when the user click on "Add item" button you can get the "template" and the index and replace the '$' with the index.
So, I not need to call the server and if the structure of the helper will change my code will still work.
It's working.

How to create side-by-side record comparison in VisualForce

The company recently came upon the need to create a side by side record comparison in Visualforce / Apex. We routinely have the need to merge leads into contacts. Previously this was handled in S-Controls; however, recent initiatives and desire to have support for our code on into the future has pushed us to move many of our S-Controls into Visualforce pages and Apex code.
We are looking to achieve something like this:
I have experimented somewhat (with little luck) doing this using the apex:pageBlockTable tag; however, I am not sure how to get two sets of data to render through when it is expecting a single SObject.
All of the prior code I have to work with was done in S-Controls using JavaScript; and while this code does work now - we need to port this to a VisualForce page. Obviously I can manually write this using HTML tables...etc but I believe that defeats the purpose of using the stock Salesforce functionality.
I'm definitely open to alternative methods - as the one i have outlined works, but requires an almost painful amount of coding to make it viable (especially as fields are updated/removed/added in the future).
The answer ended up being very straight forward!
First - As it turns out, the apex:pageBlockTable can handle pretty much any kind of object passed into the value parameter, be it an array of SObjects or an array of MyFooBar objects.
Second - we needed a wrapper class to encapsulate two records at the same time:
public with sharing class LeadContactCompareWrapper {
public static final String SALUTATION = 'Salutation';
public static final String FIRST_NAME = 'First Name';
public static final String LAST_NAME = 'Last Name';
public static final String EMAIL = 'Email';
public static final String PHONE = 'Phone';
public static final String STREET = 'Street';
public static final String CITY = 'City';
public static final String STATE = 'State';
public static final String COUNTRY = 'Country';
public static final String ZIP_POSTAL = 'Zip / Postal Code';
public static final String TITLE = 'Title';
public static final String PRIMARY_FUNCTIONAL_ROLE = 'Primary Functional Role';
public static final String SECONDARY_FUNCTIONAL_ROLE = 'Secondary Functional Role';
public static final String BULLETIN = 'Bulletin';
public static final String CREDIT_MEMO = 'Credit Memo';
public static final String FS_INSIGHTS = 'FS Insights';
public static final String MANUFAC_IND_INSIGHTS = 'Manufact. Ind Insights';
public static final String LIT_AND_FRAUD = 'Lit. & Fraud News';
public static final String REGULATORY_INSIGHTS = 'Regulatory Insights';
private Lead lead;
private Contact contact;
public List<Compare> information { get; set; }
public List<Compare> marketing { get; set; }
public List<Compare> furtherDetails { get; set; }
public List<SelectOption> names { get;set; }
public String newName { get;set; }
public Id getContactId() {
return this.contact.Id;
}
public Id getAccountId() {
return this.contact.Account.Id;
}
public Id getLeadId() {
return this.lead.Id;
}
public Lead getLead() {
return this.lead;
}
public Contact getContact() {
return this.contact;
}
public LeadContactCompareWrapper(Lead lead, Contact contact) {
this.lead = [Select Id, DeliveryPreference__c, ACE__c,AML__c,BusContinuity__c,CorpGovSOX__c,ERM__c,FinancialRisk__c,InternalAudit__c,ITAsset__c,ITAudit__c,ITSecurity__c,LitSupport__c,ORM__c,SelfAssessment__c,SpendRisk__c, Owner.Name, Company, Bulletin__c,Credit_Memo__c,FSInsights__c,Manufact_Ind_Insights__c,LitFraudNews__c,RegulatoryInsights__c, LastModifiedDate, Salutation, FirstName, LastName, Email, Phone, Street, City, State, Country, PostalCode, Title, Primary_Functional_Role__c, SecondaryFunctionalRole__c From Lead Where Id = :lead.Id];
this.contact = [Select Id, Owner.Name, Account.Id, Account.Name, Bulletin__c,Credit_Memo__c,FSInsights__c,Manufact_Ind_Insights__c,LitFraudNews__c,RegulatoryInsights__c, LastModifiedDate, Salutation, FirstName, LastName, Email, Phone, MailingStreet, MailingCity, MailingState, MailingCountry, MailingPostalCode, Title, Primary_Functional_Role__c, SecondaryFunctionalRole__c From Contact Where Id = :contact.Id];
this.init();
}
private void init() {
this.information = new List<Compare>();
this.marketing = new List<Compare>();
this.furtherDetails = new List<Compare>();
// this part will suck but it has to be done
information.add(this.createCompare(SALUTATION,
(this.lead.Salutation != null) ? this.lead.Salutation : '',
(this.contact.Salutation != null) ? this.contact.Salutation : ''
));
/* Continue adding as many compare fields for the 'information' section as needed... */
// Marking Subscriptions
marketing.add(this.createCompare(BULLETIN,
(this.lead.Bulletin__c != null) ? this.lead.Bulletin__c : '',
(this.contact.Bulletin__c != null) ? this.contact.Bulletin__c : ''
));
/* Continue adding as many compare fields for the 'marketing' section as needed... */
// Further information - just for display purposes
furtherDetails.add(this.createCompare('Owner',
(this.lead.Owner.Name != null) ? this.lead.Owner.Name : '',
(this.contact.Owner.Name != null) ? this.contact.Owner.Name : '',
false,
true
));
/* Continue adding as many compare fields for the 'further information' section as needed... */
}
/*
* Creates a comparison object
*/
private Compare createCompare(string label, String val1, String val2, Boolean isVal1, Boolean isVal2) {
Compare c = new Compare(label);
c.selectVal1 = isVal1;
c.selectVal2 = isVal2;
c.val1 = val1;
c.val2 = val2;
return c;
}
/*
* Defaults our comparison to value 1 as selected
*/
private Compare createCompare(String label, String val1, String val2) {
return createCompare(label, val1, val2, true, false);
}
}
Third - We need to create a 'compare' class that holds two values and two booleans based on which value is selected (and a row label to display on the table):
public class Compare {
public Compare (String label) {
this.label = label;
}
public String label { get; set; }
public Boolean selectVal1 { get; set; }
public Boolean selectVal2 { get; set; }
public String val1 { get; set; }
public String val2 { get; set; }
}
Then it is as simple as putting it all on a VF page with the following:
<apex:pageblocktable value="{!leadToContact.information}" var="compare">
<apex:column>
<apex:facet name="header">Information</apex:facet>
{!compare.label}
</apex:column>
<apex:column>
<apex:facet name="header">Lead</apex:facet>
<apex:inputcheckbox id="val1" label="{!compare.val1}" onclick="uncheckOtherCompare(this);" title="{!compare.val1}" value="{!compare.selectVal1}" />
<apex:outputlabel value="{!compare.val1}" />
</apex:column>
<apex:column>
<apex:facet name="header">Contact</apex:facet>
<apex:inputcheckbox id="val2" label="{!compare.val2}" onclick="uncheckOtherCompare(this);" value="{!compare.selectVal2}" />
<apex:outputlabel value="{!compare.val2}" />
</apex:column>
</apex:pageblocktable>
Finally we just need a little javascript to make the radio buttons behave properly :)
function uncheckOtherCompare(obj) {
// Get the id of the object being checked
var objId = obj.id;
if (objId.indexOf('val1') >= 0) {
objId = objId.replace('val1', 'val2');
} else {
objId = objId.replace('val2', 'val1');
}
if (obj.checked) {
document.getElementById(objId).checked = false;
} else if (!document.getElementById(objId).checked) {
// If the user is trying to uncheck both boxes, recheck the box that is being passed in.
// We can't have 'no' boxes checked on a given row
obj.checked = true;
}
}
The javascript can be placed pretty much anywhere on the page, but it's best to either link it or place it at the top of the document just after the opening tag.
Once this has been done you can (from the code) access your LeadContactCompareWrapper.[information|marking|furtherDetails] array and step through each one to determine the selected values, or write additional helper classes to expedite the process.
With this in place we were able to create a side-by-side record comparison that allowed us to merge our leads directly into our contacts!

Categories

Resources