CFGRID - replace data store or filter on more than one column - coldfusion

ColdFusion 8
I have a cfgrid that that is based on a query. It is not bound to a cfc function because I want a scrolling grid, not a paged grid (you must supply the page number and page size if you use BIND).. I can figure out how to make it filter on one column by using the following code, but I really need to filter on three columns...
grid.getDataSource().filter("OT_MILESTONE",t1);
Adding more to the filter string does not do the trick...it ignores anything more than the first pair of values..
so..I thought if I called a function that passes the three values and returned the query results to me, I could replace the Data Store for the grid..but I cannot figure out the syntax to get it to replace.
The returned variable for the query has the following format:
{"COLUMNS":["SEQ_KEY","ID","OT_MILESTONE"],"DATA":[[63677,"x","y"]]}
Any ideas?

have you looked at queryconvertforgrid()?
http://www.cfquickdocs.com/cf9/#queryconvertforgrid
Update: have you looked at these?
http://www.danvega.org/blog/index.cfm/2008/3/10/ColdFusion-8-Grid-Filtering
http://www.coldfusion-ria.com/Blog/index.cfm/2009/1/13/Playing-with-cfgrid--Filter-showhide-Columns-and-using-the-YUI-Buttons-library
http://cfsilence.com/blog/client/index.cfm/2007/8/9/Filtering-Records-In-An-Ajax-Grid

after much blood, sweat, tears and swearing..here's the answer, in case anyone else might need to filter a cfgrid by more than one variable:
var w1 = ColdFusion.getElementValue('wbs');
var t1 = ColdFusion.getElementValue('task');
var p1 = ColdFusion.getElementValue('project');
grid = ColdFusion.Grid.getGridObject('data');
store = grid.getDataSource();
store.clearFilter();
store.filterBy(function myfilter(record) {
var wantit = true;
if (trim(w1) != '') {
if(record.get('WBS_ID') != w1) {
wantit = false;
}}
if (trim(t1) != '') {
if(record.get('OT_MILESTONE') != t1) {
wantit = false;
}}
if (trim(p1) != '') {
if(record.get('PROJECT') != p1) {
wantit = false;
}}
return wantit;
});
ColdFusion.Grid.refresh('data',false);
you will need a JS trim function...
Make sure the column names are caps...

Related

i want to update only single row column value with rollback commit

i want to update only single row column value with rollback commit but when i create table object inside if and pass to insertonsubmit it gives me error,plz help me how can i solve this
var challan = dataContext.Purchase_Challans.Where(t => t.Challan_ID == Convert.ToInt64(ViewState["challanid"]) && t.Company_ID == Convert.ToInt32(Session["CompanyId"])).Select(t => t).ToList();
if (challan.Any())
{
challan.ToList()[0].Inv_DocumentId = dmsPurchaseInvoice.Document_ID;
dataContext.Purchase_Challans.InsertOnSubmit()
dataContext.SubmitChanges();
}
Would be helpful to know more details about the error, but I assume it's because you tell the dataContext to insert an entity that you just retrieved (whereas you want to update it).
Also the code you posted does not even compile and is full of questionable code, like challan.ToList() where it already is a list, or parsing strings inside a delegate.
That said, this code is more straightforward and more likely to work (but to be honest I didn't test it):
var challanId = Convert.ToInt64(ViewState["challanid"]);
var companyId = Convert.ToInt32(ViewState["CompanyId"]);
var challan = dataContext.Purchase_Challans.SingleOrDefault(t => t.Challan_ID == challanId && t.Company_ID == companyId);
if (challan != null)
{
challan.Inv_DocumentId = dmsPurchaseInvoice.Documet_Id;
dataContext.SubmitChanges();
}

Numbered lists continues when Apps Script appends template-content into document

I have an Apps Script that copies the content of an template-file to the end of a document. It works with one minor annoyance: the numbered list continues from one copy to the next.
I have many different templates that users can append to the end of the document. Each template is stored in its own Document.
function addSub(template_id){
var mainBody = DocumentApp.getActiveDocument().getBody();
var tempBody = DocumentApp.openById(template_id).getBody();
for(var i = 0;i<tempBody .getNumChildren();i++){
var element = tempBody .getChild(i);
if(element.getType() == DocumentApp.ElementType.TABLE)
mainBody.appendTable(element.copy());
else if(element.getType() == DocumentApp.ElementType.PARAGRAPH)
mainBody.appendParagraph(element.copy());
else if(element.getType() == DocumentApp.ElementType.LIST_ITEM)
mainBody.appendListItem(element.copy());
else if(element.getType() == DocumentApp.ElementType.PAGE_BREAK)
mainBody.appendPageBreak(element.copy());
}
}
It could look like this: ( I want the list to reset for each new copy of the template)
table with name of this template
some raw text
List item1
List item2
table with name of this template
some raw text
List item1
List item2
Do you now that ListItems have an ID, which is a STRING and you can access it via myListItem.getListId().
It seems that all your ListItems have the same ID.
If this is the case, the numbering has to be as you described.
Why do they have the same ListID?
I don't know.
Seems that the body.appendListem method always chooses the same listId.
I didn't test it yet, but you could try to set the listID of the newly append ListItem to that of the original document, if they are different.
Yes, i know, the .copy() method should enclose this information, but the body.appendListItem method may not care.
So, you could try to first save the detached copy of the listItem.
Then append it to the new body.
And then set the id of the newly appended listItem to that of the detached copy.
It's stupid, i know, but it may help.
Didn't try it yet.
And i have little experience with listItems, bit what i saw up to now is that there seems to be only one ListId in the body of a document, if you append or insert listItems.
This could be the cause of the problem.
Hope this helps.
After Richard Gantz solved it, It was corrected by this code:
var listItemDictionary = {};//top
...
else if(element.getType() == DocumentApp.ElementType.LIST_ITEM){
var listCopy = element.copy().asListItem()
var lcID = listCopy.getListId();
if (listItemDictionary[lcID] == null){
var tempLI = mainBody.appendListItem("temp")
listItemDictionary[lcID] = tempLI;
}
Logger.log(lcID)
mainBody.insertListItem(childIndex+j, listCopy.setListId(listItemDictionary[lcID]));
}
...
if(listItemDictionary){//bottom
mainBody.appendParagraph("");
for(var key in listItemDictionary){
listItemDictionary[key].clear().removeFromParent()
}
}
Based on the answer from Niklas Ternvall/Richard Gantz, I found a simpler solution for the case of each template having no more than one list.
function addSub(template_id) {
var mainBody = DocumentApp.getActiveDocument().getBody();
var tempBody = DocumentApp.openById(template_id).getBody();
var listID = null;
for(var i = 0;i<tempBody.getNumChildren();i++){
var element = tempBody.getChild(i).copy();
var type = element.getType();
if(type == DocumentApp.ElementType.TABLE)
mainBody.appendTable(element);
else if(type == DocumentApp.ElementType.PARAGRAPH)
mainBody.appendParagraph(element);
else if(type == DocumentApp.ElementType.LIST_ITEM){
if(listID==null) // First list item
listID = mainBody.appendListItem('temp'); // Define new listID
mainBody.appendListItem(element).setListId(listID); // Apply to copy
}
else if(type == DocumentApp.ElementType.PAGE_BREAK)
mainBody.appendPageBreak(element);
}
mainBody.removeChild(listID); // Delete temporary list item
}
Each time you call the function, listID=null is the indicator for whether or not there have been any list items in the template. When you get to the first list item, appending the text 'temp' forces a new list and hence a new listID that you can apply to the list items from the template. After you finish going through the template, mainBody.removeChild(listID) removes 'temp' from the top of your list.
This solution worked for me when using one template 100 times in one document, essentially as a mail merge. I'm fairly new to Apps Script, so I would appreciate any feedback if there is a reason this wouldn't work for a single-list template.

How do I query multiple IDs via the ContentSearchManager?

When I have an array of Sitecore IDs, for example TargetIDs from a MultilistField, how can I query the ContentSearchManager to return all the SearchResultItem objects?
I have tried the following which gives an "Only constant arguments is supported." error.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(x => f.TargetIDs.Contains(x.ItemId));
rpt.DataBind();
}
I suppose I could build up the Linq query manually with multiple OR queries. Is there a way I can use Sitecore.ContentSearch.Utilities.LinqHelper to build the query for me?
Assuming I got this technique to work, is it worth using it for only, say, 10 items? I'm just starting my first Sitecore 7 project and I have it in mind that I want to use the index as much as possible.
Finally, does the Page Editor support editing fields somehow with a SearchResultItem as the source?
Update 1
I wrote this function which utilises the predicate builder as dunston suggests. I don't know yet if this is actually worth using (instead of Items).
public static List<T> GetSearchResultItemsByIDs<T>(ID[] ids, bool mustHaveUrl = true)
where T : Sitecore.ContentSearch.SearchTypes.SearchResultItem, new()
{
Assert.IsNotNull(ids, "ids");
if (!ids.Any())
{
return new List<T>();
}
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<T>();
predicate = ids.Aggregate(predicate, (current, id) => current.Or(p => p.ItemId == id));
var results = s.GetQueryable<T>().Where(predicate).ToDictionary(x => x.ItemId);
var query = from id in ids
let item = results.ContainsKey(id) ? results[id] : null
where item != null && (!mustHaveUrl || item.Url != null)
select item;
return query.ToList();
}
}
It forces the results to be in the same order as supplied in the IDs array, which in my case is important. (If anybody knows a better way of doing this, would love to know).
It also, by default, ensures that the Item has a URL.
My main code then becomes:
var f = (Sitecore.Data.Fields.MultilistField) rootItem.Fields["Main navigation links"];
rpt.DataSource = ContentSearchHelper.GetSearchResultItemsByIDs<SearchResultItem>(f.TargetIDs);
rpt.DataBind();
I'm still curious how the Page Editor copes with SearchResultItem or POCOs in general (my second question), am going to continue researching that now.
Thanks for reading,
Steve
You need to use the predicate builder to create multiple OR queries, or AND queries.
The code below should work.
using (var s = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
foreach (var targetId in f.Targetids)
{
var tempTargetId = targetId;
predicate = predicate.Or(x => x.ItemId == tempTargetId)
}
rpt.DataSource = s.GetQueryable<SearchResultItem>().Where(predicate);
rpt.DataBind();
}

Linq query not matching hrefs

I'm trying to write out all matches found using a regex with the code below:
var source = "<Content><link><a xlink:href=\"tcm:363-48948\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">Read more</a></link><links xlink:href=\"tcm:362-65596\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"/></Content>";
var tridionHref = new Regex("tcm:([^\"]*)");
var elem = XElement.Parse(source);
XNamespace xlink = "http://www.w3.org/1999/xlink";
if (tridionHref.IsMatch(elem.ToString()))
{
foreach (var Id in elem.Elements().Where(x => x.Attribute(xlink + "href") != null))
{
Console.WriteLine(Id.Attribute(xlink + "href").Value); //For testing
Id.Attribute(xlink + "href").Value = Id.Attribute(xlink + "href").Value.Replace("value1", "value2"); //Just to show you an example
}
}
My console window outputs tcm:362-65596 but not tcm:363-48948. It looks like the code doesn't see the value of xlink:href inside my <a> tag as an attribute? Can anyone point me in the right direction? I need to match ALL instances of tcm:([^\"]*).
The problem is you are not looking in the right place. Your elem.Elements is looking at the link element and the links element. Only one of these has the attribute that you are looking for. You'll need to select the elements you want to check more precisely before looking for the right attribute.
I've got it working. I didn't need a regex I just needed to get the Descendants instead inside my for loop. foreach (var Id in elem.Descendants().Where(x => x.Attribute(xlink + "href") != null))

Replicating Google Analytics DateRange picker

I need to replicate the Google Analytics date picker (plus a few new options). Can anyone tell me how to highlight all the cells on a calendar between two dates. My basic JavaScript is OK but I think I'm getting a bit out of my depth.
I'm using JQuery 1.5.1 and JQuery UI 1.8.14.
In needed to replicate Google Analytics date picker as well. I know you were asking just about highlighting cells, but if someone else would prefer complete solution, you can see my answer from another question: jquery google analytics datepicker
Here's a solution using the built-in 'onSelect' event (jsFiddle):
$(document).ready(function() {
'use strict';
var range = {
'start': null,
'stop': null
};
$('#picker').datepicker({
'onSelect': function(dateText, inst) {
var d, ds, i, sel, $this = $(this);
if (range.start === null || range.stop === null) {
if (range.start === null) {
range.start = new Date(dateText);
} else {
range.stop = new Date(dateText);
}
}
if (range.start !== null && range.stop !== null) {
if ($this.find('td').hasClass('selected')) {
//clear selected range
$this.children().removeClass('selected');
range.start = new Date(dateText);
range.stop = null;
//call internal method '_updateDatepicker'.
inst.inline = true;
} else {
//prevent internal method '_updateDatepicker' from being called.
inst.inline = false;
if (range.start > range.stop) {
d = range.stop;
range.stop = range.start;
range.start = d;
}
sel = (range.start.toString() === range.stop.toString()) ? 0 : (new Date(range.stop - range.start)).getDate();
for (i = 0; i <= sel; i += 1) {
ds = (range.start.getMonth() + 1).toString() + '/' + (range.start.getDate() + i).toString() + '/' + (range.start.getFullYear()).toString();
d = new Date(ds);
$this.find('td a').filter(function(index) {
return $(this).text() === d.getDate().toString();
}).parents('td').addClass('selected');
}
}
}
}
});
});
I became desperate and came up with a solution on my own. It wasn't pretty but I'll detail it.
I was able to construct a div that had the text boxes, buttons and the datepicker that looked like the Google Analytics control but I couldn't make the datepicker work properly. Eventually, I came up with the idea of creating a toggle variable that kept track of which date you were selecting (start date or end date). Using that variable in a custom onSelect event handler worked well but I still couldn't figure out how to get the cells between dates to highlight.
It took a while, but I slowly came to the realization that I couldn't do it with the datepicker as it existed out of the box. Once I figured that out, I was able to come up with a solution.
My solution was to add a new event call afterSelect. This is code that would run after all the internal adjustments and formatting were complete. I then wrote a function that, given a cell in the datepicker calendar, would return the date that it represented. I identified the calendar date cells by using jQuery to find all the elements that had the "ui-state-default" class. Once I had the date function and a list of all the calendar cells, I just needed to iterate over all of them and, if the date was in the correct range, add a new class to the parent.
It was extremely tedious but I was able to make it work.