Calculate layout delta to store on an item - sitecore

I am trying to figure out how to calculate, then store the layout delta for a rendering programatically. The situation I'm in is that I have a rendering defined on my standard value. It's datasource is empty. I then have a process that creates an item based on that template, but I need to set the datasource on the rendering.
By default, the __Renderings field on the new item is blank (as is expected). So far, I've been able to get a RenderingReference to my rendering, detect that the datasource is blank, but I cannot for the life of me figure out how to set the datasource then store the correct delta in the __Renderings field on my item.
So far I have:
foreach (var device in new DeviceRecords(database).GetAll())
{
foreach (var rendering in myItem.Visualization.GetRenderings(device, false).Where(r => r.RenderingID == renderingId)
{
if (rendering.Settings.DataSource.IsNullOrEmpty())
{
var dataSourceItem = datasourceFolder.Add("Datasource name", dataSourceTemplate);
rendering.Settings.DataSource = dataSourceItem.ID.ToString();
using (new EditingContext(myItem)){
myItem[FieldIDs.LayoutField] == //????
}
}
}
}
My guess is I need to somehow invoke something in XmlDelta, but it looks like all of those methods want some Xml to work with, when all I have is the rendering item.

I wrote some code a while back that tried to extract data source information from Sitecore's XML deltas. I never tried updating it though, but this may work for you.
The class I used was Sitecore.Layouts.LayoutDefinition which is able to parse the XML and if I remember correctly it deals with the business of working out what the correct set of page controls is by combining the delta with the underlying template data. You can construct it like so:
string xml = LayoutField.GetFieldValue(item.Fields["__Renderings"]);
LayoutDefinition ld = LayoutDefinition.Parse(xml);
DeviceDefinition deviceDef = ld.GetDevice(deviceID);
foreach(RenderingDefinition renderingDef in deviceDef.GetRenderings(renderingID))
{
// do stuff with renderingDef.Datasource
}
So I think you can then use the API that LayoutDefinition, DeviceDefinition and RenderingDefinition provides to access the data. There's a bit more info on how I used this in the processImages() function in this blog post: https://jermdavis.wordpress.com/2014/05/19/custom-sitemap-filespart-three/
I think the missing step you're after is that you can modify the data this object stores (eg to set a data source for a particular rendering) and then use the ToXml() method to get back the revised data to store into your Renderings field?
You may be able to find more information by using something like Reflector or DotPeek to look inside the code for how something like the Layout Details dialog box modifies this data in the Sitecore UI.
-- Edited to add --
I did a bit more digging on this topic as I was interested in how to save the data again correctly. I wrote up what I discovered here: https://jermdavis.wordpress.com/2015/07/20/editing-layout-details/

Related

Using jqGrid I need to Show a Hidden Column Based on UserData Parm

Using jqGrid 4.15.6-pre - free jqGrid
I am wondering why the following code will not show the specified column.
var cm = $('#nrtslist').jqGrid('getColProp','override');
cm.hidden = false;
This can't be done this way.
All the concept of the grid is that you can read the properties of colModel or any other grid option, but changing it does not mean that it will change something. With other words something must happen in order to change the property.
These properties describe the current status (in most cases) or this is a consequence, not a cause.
To change something in grid you will need to use the appropriate method or do your own one.
In your case you will need to use the showCol or hideCol methods
$('#nrtslist').jqGrid('showCol','override'); // this will show the column
$('#nrtslist').jqGrid('hideCol','override'); // this will hide it.

Ultragrid entire column selection when header is clicked

This might seem a very easy problem but I am stuck and can't find a way out of it. I am using ultragrid in my form with several columns. My issue is when I am trying to click on the column header I am expecting my entire column to be selected but it doesn't. I assumed the SelectTypeCol is the property for my column selection but it did not work either. I also tried to add each column to Selected.Columns collection like this UltraGrid1.DisplayLayout.Bands(0).Columns(i).Header.Selected = True but it didn't work for me either. I believe Selected is only available during runtime but not at the design mode.
So if there is an easier way to make this work, please let me know.
Thank you
You are looking for the property HeaderClickAction
grid.DisplayLayout.Override.HeaderClickAction = HeaderClickAction.Select
This will automatically flip the selection state of the entire column as Selected (or Delected) when you click on the header. Of course this means also that you loose the ability to automatically sort on all columns
You can programmatically set the Selection state of a column with code like this (C#)
grid.DisplayLayout.Bands[0].Columns["youColumnKey"].Header.Selected = true;
this will permit to leave the HeaderClickAction property to SortSingle or SortMulti, but you have to handle the situation using code and appropriate events
You need to have an InitializeLayout event on your grid. in this event you need to set the chekboxsynchronization to default and it should work here is sample code
private void ultraGrid1_InitializeLayout(object sender,
Infragistics.Win.UltraWinGrid.InitializeLayoutEventArgs e)
{
e.Layout.Bands[0].Columns.Add("CheckBox");
e.Layout.Bands[0].Columns["CheckBox"].Style = ColumnStyle.CheckBox;
e.Layout.Bands[0].Columns["CheckBox"].Header.CheckBoxVisibility = HeaderCheckBoxVisibility.WhenUsingCheckEditor;
e.Layout.Bands[0].Columns["CheckBox"].Header.CheckBoxSynchronization = HeaderCheckBoxSynchronization.Default; <-- make sure it is set to default here
}

Qt models behind proxies and fetchMore()/canFetchMore()

I am interested to know how would views behave in cases when the main data model with incremental data fetching is behind a proxy or chain of proxies.
How proxy which does item rearrangements like ungrouping proxy (example: http://lynxline.com/jongling-qt-models/) should implement support of fetchMore()/canFetchMore()?
Examining QSortFilterProxyModel's source allows me to conclude that:
QSortFilterProxyModel allows access to already fetched rows. Calling rowCount, data, etc. will behave like there is no more data in the source table.
QSortFilterProxyModel (and QAbstractProxyModel by default) routes canFetchMore and fetchMore calls to according methods of the source model.
It means that when you scroll down a view with a QSortFilterProxyModel populated from a dynamically fetched table, it will be dynamically populated with new data from source model. However you can't be sure that new items will be added to the end. Instead, when scrolling down the table, its data can completely change. New rows can be added anywhere depending on current sorting and filtering settings.
When no additional support of canFetchMore and fetchMore is given, all proxy models (including the linked UngroupProxyModel class) will behave like that by default.
QTableView behaves buggy displaying such models. For example, if the source model has rows -2; -3; 2; 3 (let ; be a row separator in my answer), the view without sorting would usually display something like -2; -3; 2; 3; empty row; empty row. Empty rows are displayed in the bottom of the table. When user scrolls down enough close to these items, the view requests fetching more data. However, when sorting is enabled, the view shows -3; -2; empty row; empty row; 2; 3, i.e. it moves empty invalid rows to the middle or to the top of the table. It doesn't affect functionality but looks awkward.
However, all aforementioned issues are implementation dependent. Refer to the code and documentation of the used model classes for more details. I think it's possible to implement proxy models that act however you like.
Also, it would be reasonable in some cases to fetch source model completely before displaying sorted data in the table. Proper sorting or joining is impossible while not all data has been fetched. If you fetched the source model data (e.g. while(model->canFetchMore()) { model->fetchMore(); }) then proxy models will behave exactly like the model is not dynamically populated.

Filtered array of local Model records

I have an array controller ActivitiesController which is responsible for managing a days worth of activities (versus the full set). I've set the model property of the ActivitiesRoute to the following:
return this.store.find('activity', {on_date: params.on_date});
This does pull back the appropriate records and I can see them all within the Ember debugger but for some reason these records aren't available to the template (activities.hbs). That was baffling to me but in reality that isn't the final solution anyway (i had just expected it to work).
What I really want to do is have the controller's content manage an array of local Activity records that have been filtered to the specified date. This filtered array then will periodically update based on asynchronous calls to an update query: find('activity', {on_date: this.get('on_date'), since: this.get('since');.
I hope that description makes sense. I've looked at other queries on SO and there were some promising starts but the answers all seemed to be dated and I could find anything that helped me crack this nut.
In summary, I want to:
Have the controller's content be an active filter on the local Activity records that correspond to a given date.
Be able to asynchronously push additional records onto the model which will automagically show on the controller (assuming they're for the appropriate date).
As an aside, I'd be particularly interested to know why my current model hook isn't available the activities template.
------------- UPDATE -------------
I have tried this in my model hook:
return this.store.filter('activity',function(activity){
var itemDate = new Date(activity.get('start_time'));
itemDate = moment(itemDate).format('YYYY-MM-DD');
return itemDate === params.on_date;
});
This should be inline with #Bradley's suggestion. I needed to truncate the time component so I added that logic using the moment.js library. This doesn't throw any errors but also doesn't pull any records from the server by itself so I added the following line of code into the model hook:
this.set('activities', this.store.find('activity', {on_date: params.on_date}));
Using the debugger I can see that the ActivityRoute has an activities property that is set as a DS.PromiseArray and I can see that the activities property has a length of 15 which is the number of activities for that day.
It also looks like the currentModel of ActivityRoute is set to a DS.FilteredRecordArray and it too has the appropriate 15 records in it but my handlebars template still has no ability to iterate over it. I assume this is because the content property of the ActivityController is not set. Why is this step not done by Ember in this situation? Do I need to force this or are there gremlins in the system that need teasing out?
For local filtering you are looking for the DS.Store#filter function.
return this.store.filter('activity', function(activity) {
activity.get('on_date') === params.on_date
});
This returns a DS.FilteredRecordArray that live-updates with new/updated records

Titanium refreshing TableView with new data

This is what I am trying to do:
_tableView.data[0].rows[selectedPosY].children[selectedPosX].imageId = tempImageId;
_tableView.data[0].rows[selectedPosY].children[selectedPosX].image = tempImageUrl;
Titanium.API.info("imageIdSelected:" +
_tableView.data[0].rows[selectedPosY].children[selectedPosX].imageId + "imageSelected:" +
_tableView.data[0].rows[selectedPosY].children[selectedPosX].image);
The update is done on the data, but it doesn't reflect in UI table, what is missing?
I even tried doing the below as per How can I refresh my TableView in titanium? & How to resolve Titanium TableView display problem?, but it is not refreshing the UI table
_tableView.setData(_tableView.data); win.add(_tableView);
It turns out the only way to update/reload a Titanium.UI.TableView is to get a copy of the updated data (as per ones logic) and reset it in the TableView, using 'setData'. For my example, since the _tableView.data is getting updated (which could be seen through the logging statements), I could copy it using a javascript array copy function like;
var data2 =_tableView.data.slice(0);
_tableView.setData(data2);
Although, with the above knowledge, I had restructure my code, so, I am not using this exact code, but a similar logic. But, overall, this way of updating the table doesn't seem very appealing, if there is any better way of handling this, please post, it would help a lot.
Why are you doing _tableView.data[0].rows and then just _tableView.data when using setData?
Your _tableView.data should be an array of rows/sections. The Ti.UI.tableView object has the data property but the data should be structured as follows.
_tableView.data = [
{title:"Row 1"},
{title:"Row 2"}
];
What does the .rows accomplish for you when you are doing it that way, how are you using the .rows? I'm not positive but I think the _tableView.data is either no different or is invalid when trying to setData.