in the below code the datasource is coming as null for all the renderings present in presentation details, please help me where i am going wrong
LayoutDefinition layout =
LayoutDefinition.Parse(bioItem[Sitecore.FieldIDs.LayoutField]);
foreach (DeviceDefinition device in layout.Devices) {
if (device.Renderings != null) {
for(var i =0; i < device.Renderings.Count;i++) {
RenderingDefinition rendering = (RenderingDefinition)device.Renderings[i];
var result = rendering.Datasource;
}
}
}
First of all you should know there are two layout fields:
Shared: Sitecore.FieldIDs.LayoutField
Final: Sitecore.FieldIDs.FinalLayoutField
i usually use this code snippet to read directly from layout:
var devices = dataItem.Database.Resources.Devices;
var defaultDevice = devices.GetAll().First(d => d.Name.ToLower() == ScConstants.DefaultDeviceName);
var renderings = dataItem.Visualization.GetRenderings(defaultDevice, true);
foreach (var rendering in renderings)
{
if (!string.IsNullOrWhiteSpace(rendering?.Settings.DataSource))
{
var datasource = dataItem.Database.GetItem(rendering.Settings.DataSource, dataItem.Language);
.....
There are other ways to read the Layout field, but i suggest you to using the provided API and keep the layout XML parsing as the last resort.
Related
Hello and thanks in advance for your help,
I find many other topics about this, but I did not find answers to my problem, so here I am.
My goal is to automaticly create dropdow lists in a board (between 50-100 drop down list), according to a word in another column. The data should be in another spreadsheet, and most of the dropdown list could go around 600-700 items.
Please check in picture below for more explainations :
board picture
The dropdown list 1 and 2 are created in column G and H if it does find a sheet name in the first word of the column F "designation". If you pick an item of colum G "Libellés", it makes a Vlookup for column "MP" and price in the designated sheet. Same if you pick an item in of column "MP", it makes a Vlookup in "Libellés" and "price" to match.
This is working fine when all sheets are in the same spreadsheet, but I can't find a way to make it work when all data sheets are in another spreadsheet. The spreadsheet with the code will be copy many times (200+ each year), so I want to put the database sheets (15000+lignes x 5 columns) in only one spreadsheet that feeds all others "small" spreadsheets when we open those.
I tryed many options :
requireValueInList : This is not working, some lists are 600-700 items, not working with big lists like this.
list from a range : Ranges are too big, and I have around 50-100 dropdown list of 100-700 items, this is too much, program stops before the end (and I have a good computer, which is not the case of most of my colleagues), so this is not a solution, or I am doing it wrong.
requireValueInRange : This is what I am using to make it run when everything is on the same spreadsheet, but can't use it if datas are on another spreadsheet.
Is there a way to get around requireValueInRange limitation? This is the first time I use google app script so please don't judge too harshly.
here is the code, it is working fine when all data sheets are in the same sspreadsheet as the target sheet for drop dow list:
function onOpen(e) {
// sss for source spreadsheet where I have all datas, and tss for target spreadsheet where I want my lists to be created
var sss1 = spreadsheetApp.openById('blahblah');
var ssh1 = sss1.getSheetByName('Emballages');
var tss = SpreadsheetApp.getActiveSpreadsheet();
var tsh = tss.getActiveSheet();
var tsh1 = tss.getSheetByName('Fiche_eclate_CS');
// The below part is to update 2 lists, using datas from the sheet "emballages" in the source spreadsheet, all working fine except data validation rule, won't accept arguments
var sheet = tss.getSheets()[0];
var column = sheet.getRange("F:F").getValues();
var prow;
for (var i = 0; i < column.length; i++){
if (column[i][0] === "Packaging :") {
prow = i+1;
break;
}
}
var emblrow = ssh1.getRange('B:B').getLastRow();
var cel1D = tsh1.getRange(prow,7);
// This is where I have problems. The call ('B2:B'+ emblrow) is not accepted. I can't use this as data validation on another spreadsheet.
var cel2D = ssh1.getRange('B2:B'+ emblrow);
var ruleD = SpreadsheetApp.newDataValidation().requireValueInRange(cel2D).build();
cel1D.setDataValidation(ruleD);
var cel1M = tsh1.getRange(prow,8);
// Same problem here. The call ('A2:A'+ emblrow) is not accepted.
var cel2M = ssh1.getRange('A2:A'+ emblrow );
var ruleM = SpreadsheetApp.newDataValidation().requireValueInRange(cel2M).build();
cel1M.setDataValidation(ruleM);
// The below part is to update many lists, using datas from one sheet in the source spreadsheet. To find the good sheet in the other spreadsheet, I use the split function. This part is working fine. I only have problems with data validation rules, same as above.
var ui = SpreadsheetApp.getUi();
var button = ui.alert("Voulez vous mettre à jour toutes les listes de la feuille ?",ui.ButtonSet.YES_NO);
if (button == ui.Button.YES) {
var anchhrow;
var anchbrow;
var column1 = tsh1.getRange("B:B").getValues();
for (var i = 0; i < column1.length; i++){
if (column1[i][0] === "Anchor-haut") {
anchhrow = i+3;
break;
}
}
for (var i = 0; i < column1.length; i++){
if (column1[i][0] === "Anchor-bas") {
anchbrow = i;
break;
}
}
var rangeH1 = tsh.getRange('H'+anchhrow +':H'+anchbrow).getValues();
var range = tsh.getRange('H'+anchhrow +':H'+anchbrow);
var lrowH = rangeH1.length;
for (var k=0; k<lrowH; k++){
var rown = anchhrow + k;
var testrng = sheet.getRange("F" + rown);
if ( testrng == "" ) {
}
else {
var name = nom(tsh,rown);
var ssh3 = sss1.getSheetByName(name);
if (ssh3 == null){
}
else {
var flrow = ssh3.getRange('B2:B').getLastRow();
var rng1D = tsh1.getRange(k+anchhrow,7);
// same issu, can't use ('B2:B'+ flrow)for data validation
var rng2D = ssh3.getRange('B2:B'+ flrow);
var ruleD =
SpreadsheetApp.newDataValidation().requireValueInRange(rng2D).build();
rng1D.setDataValidation(ruleD);
var rng1M = tsh1.getRange(k+anchhrow,8);
// same here, can't use ('A2:A'+ flrow)for data validation
var rng2M = ssh3.getRange('A2:A'+ flrow );
var ruleM = SpreadsheetApp.newDataValidation().requireValueInRange(rng2M).build();
rng1M.setDataValidation(ruleM);
}
}
}
function nom(sheet,row){
var word = [{}];
var rng = sheet.getRange("F" + row);
var word = rng.getValue().split(" ");
Logger.log(word);
return word[0];
}
}
else {
}
// This part is where I control prices once all lists are updated, this is working fine.
var ui = SpreadsheetApp.getUi();
var button = ui.alert("Les listes ont été mises à jour. Voulez vous mettre à jour les prix ?",ui.ButtonSet.YES_NO);
if (button == ui.Button.YES) {
for(var j=0;j<lrowH; j++){
var cellI1 = tsh.getRange(j+anchhrow,8).getValue();
if (cellI1 == "") {
}
else {
var cellI2 = vlookup(ssh2,1,3,cellI1);
tsh.getRange(j+anchhrow,9).setValue(cellI2);
function vlookup(sheet, column, index, value) {
var lastRow=sheet.getLastRow();
var data=sheet.getRange(1,column,lastRow,column+index).getValues();
for(i=0;i<data.length;++i){
if (data[i][0]==value){
return data[i][index];
}
}
}
}
}
}
else {
}
Browser.msgBox ("MAJ feuille terminée");
}
Feel free to ask questions if there are stuffs you don't understand or if you need more details.
Thanks in advance,
The main issue you are encountering is due to the fact that you are calling the getActiveSpreadsheet method instead of the openById(id).
However, assuming that you have the same names for the sheets but they're just in different spreadsheets and you want to keep on using the requireValueInRange method, I suggest you add the following lines to your code:
Code
function createDataValidation() {
let spreadsheetIds = ['SS_1_ID', 'SS_2_ID', ...];
for (let i=0; i<spreadsheetIds.length; i++) {
var tss = SpreadsheetApp.openById(spreadsheetIds[i]);
var tsh = tss.getActiveSheet();
var tsh1 = tss.getSheetByName('Fiche_eclate_CS');
// the rest of your code
}
}
The code above is looping through all the spreadsheets - this is done by storing all the ids of the spreadsheets you want to use in the spreadsheetIds variable and afterwards, by using a for loop, is accessing each one of them and using the code you already have.
Reference
Apps Script SpreadsheetApp Class - openById.
I suggest
function betweenSpreadsheets() {
let localSs = SpreadsheetApp.getActiveSpreadsheet();
let distSsUrl = 'https://docs.google.com/spreadsheets/d/1H-Zh blah blah KHP7x8/edit?usp=sharing';
let distSsId = '1H-Zh blah blah KHP7x8';
let distSs1 = SpreadsheetApp.openById(distSsId)
let distSs2 = SpreadsheetApp.openByUrl(distSsUrl)
}
Then proceed as if the sheets were in the same spreadsheet.
I am trying to fetch all the selected records from the interactive grid in Oracle APEX by writing the below piece of code. I have also declared #myStaticIgId as the static Id of my report.
var record, USER_NAME;
var x = '';
var l_role = $v("P2_ROLE");
var l_justification = $v("P2_JUSTIFICATION");
var l_date = $v("P2_DATE");
//Identify the particular interactive grid
var ig$ = apex.region("myStaticIgId").widget();
//Fetch the model for the interactive grid
var grid = ig$.interactiveGrid("getViews","grid");
//Fetch the model for the interactive grid
var model = ig$.interactiveGrid("getViews","grid").model;
//Fetch selected records
var selectedRecords = apex.region("myStaticIgId").widget().interactiveGrid("getViews","grid").view$.grid("getSelectedRecords");
alert(selectedRecords.length);
//Loop through selected records
for (idx=0; idx < selectedRecords.length; idx++) {
//Get the record
record = model.getRecord(selectedRecords[idx][0]);
alert(record);
//Get the current value for USER_NAME
USER_NAME = model.getValue(record,"USER_NAME");
// USER_NAME = 'Abha';
alert('submit 2');
}
The alert statement that I have written for returning the record value, returns NULL to me.
Can you please suggest, what needs to be done so as to get the proper record value in record variable.
Regards,
Abha
Finally, I got it working. the issue was the ordering of the primary key column. The primary key column should be the first column in the list after "APEX$ROW_SELECTOR" and "APEX$ROW_ACTION".
My column "ASSIGNMENT_NUMBER" with the primary key was not the first column while column "USER_NAME" was the first column in the REgions. Hence it was working for USER_NAME and not for "ASSIGNMENT_NUMBER". After changing the order of this column as first column, It worked.
Hope this also helps somebody!
I tested your code (with some changes) here and works.
1 - Define the region ID of your Interactive Grid.
2 - Go to chrome -> open console (press F12) -> try this code:
var gridID = "orders";
var ig$ = apex.region(gridID).widget();
var grid = ig$.interactiveGrid("getViews","grid");
var model = ig$.interactiveGrid("getViews","grid").model;
var selectedRecords = grid.getSelectedRecords();
for (idx = 0; idx < selectedRecords.length; idx++) {
record = model.getRecord(selectedRecords[idx][0]);
console.log(record);
console.log(model.getValue(record,"USER_NAME"));
}
I tested this code in this page: https://apex.oracle.com/pls/apex/f?p=145797:8
I am also having similar issue. Flag is "Selected List"(Yes/No). I am trying to change Flag value from "No" to "Yes" for selected Rows, However value is not getting changed.
I am using below code.
function changeFlag(){
var isVerified;
var ig$ = apex.region("New").widget();
var grid = ig$.interactiveGrid("getViews","grid");
var model = ig$.interactiveGrid("getViews","grid").model;
var selectedRecords = apex.region("New").widget().interactiveGrid("getViews","grid").view$.grid("getSelectedRecords");
for (idx=0; idx < selectedRecords.length; idx++) {
record = model.getRecord(selectedRecords[idx][0]);
console.log(record);
isVerified = model.getValue(record,"FLAG");
console.log(isVerified);
if (isVerified === 'N') {
model.setValue(record,"FLAG", 'Y');
}
}
}
Sample application is available in this link
I am not understanding where i made issue.
Actual issue is Update the flag for bulk records using IG. I am trying to change the value to "Yes" and then will save the records. I am stuck because of this issue.
Is it possible to get __Rendering control's template field value on content item?
Especially, I'd like to get "Data Source" field value defined in control on page item, like below screenshot.
As shown in screenshot, I have some controls in page item and I'd like to get control's "Data Source" field value.
I used this code and I could list all controls using on the page item. But, I don't know how to get the control's browsed data-source information on the page.
public RenderingReference[] GetListOfSublayouts(string itemId, Item targetItem)
{
RenderingReference[] renderings = null;
if (Sitecore.Data.ID.IsID(itemId))
{
renderings = targetItem.Visualization.GetRenderings(Sitecore.Context.Device, true);
}
return renderings;
}
public List<RenderingItem> GetListOfDataSource(RenderingReference[] renderings)
{
List<RenderingItem> ListOfDataSource = new List<RenderingItem>();
foreach (RenderingReference rendering in renderings)
{
if (!String.IsNullOrEmpty(rendering.Settings.DataSource))
{
ListOfDataSource.Add(rendering.RenderingItem);
}
}
return ListOfDataSource;
}
RenderingReference[] renderings = GetListOfSublayouts(targetItem.ID.ToString(), targetItem);
List<RenderingItem> ListOfDataSource = GetListOfDataSource(renderings);
This is exactly what I wanted.
Perfectly working!!!!!!
public IEnumerable<string> GetDatasourceValue(Item targetItem)
{
List<string> uniqueDatasourceValues = new List<string>();
Sitecore.Layouts.RenderingReference[] renderings = GetListOfSublayouts(targetItem.ID.ToString(), targetItem);
foreach (var rendering in renderings)
{
if (!uniqueDatasourceValues.Contains(rendering.Settings.DataSource))
uniqueDatasourceValues.Add(rendering.Settings.DataSource);
}
return uniqueDatasourceValues;
}
}
Here is a blog post that can help: Using the Data Source Field with Sitecore Sublayouts
Here's the relevant code you can call from within a single control:
private Item _dataSource = null;
public Item DataSource
{
get
{
if (_dataSource == null)
if(Parent is Sublayout)
_dataSource = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);
return _dataSource;
}
}
Accesing the DataSource property defined above will give you the item that is assigned as the Data Source from the CMS.
How do i create a Field value for a Particular Item in a Particular Language? I have an Excel that has all the item Names inside the RootItem .These Items exist in a en-US language Already. i need add values for a particular field for other languages.. Like en-GB, nl-NL, it-IT.
I have a List like
ItemName Language Translation
TestItem en-GB Hello
TestItem nl-NL Hallo
and so on..
The only problem is, when i do item.Add, it creates a new item rather than adding the value to the existing item. How can i handle this?
My code is as follows:
foreach (DataRow row in dt.Rows)
{
Language language = Language.Parse(languageId);
var rootItem = currentDatabase.GetItem(RootItemPath, language);
var item = rootItem.Add(itemName, templateItem);
if (item != null)
{
item.Fields.ReadAll();
item.Editing.BeginEdit();
try
{
//Add values for the fields
item.Fields["Translation"].Value = strTranslationValue;
}
catch (Exception)
{
item.Editing.EndEdit();
}
}
}
Try This:
var rootItem = currentDatabase.GetItem(RootItemPath);
foreach (DataRow row in dt.Rows)
{
Language language = Language.Parse(languageId);
var itemInCurrentLanguage = rootItem.Children.Where(i=>i.Name == itemName).FirstOrDefault();
if(itemInCurrentLanguage == null){
itemInCurrentLanguage = rootItem.Add(itemName, templateItem);
}
var itemInDestinationLanguage = currentDatabase.GetItem(itemInCurrentLanguage.ID, language );
if (itemInDestinationLanguage != null)
{
itemInDestinationLanguage.Fields.ReadAll();
itemInDestinationLanguage.Editing.BeginEdit();
try
{
//Add values for the fields
itemInDestinationLanguage.Fields["Translation"].Value = strTranslationValue;
}
catch (Exception)
{
//Log any error
}
finally
{
itemInDestinationLanguage.Editing.EndEdit();
}
}
}
You need to switch the language before you get the root item:
using (new LanguageSwitcher(language))
{
var rootItem = currentDatabase.GetItem(RootItemPath);
var item = rootItem.Add(selectedItem.Name, CommunityProjectTemplateId);
// Add new item here...
}
in order to get familiar with dojo I'm working on a test project which consists of the following components:
data grid (created declaratively), filled with JSON data; clicking on a line will open a dialog containing a form (works)
form (created from template), with several input fields, filled with data from the grid store (works)
FilteringSelect (part of form) (doesn't work, no content)
The FilteringSelect contains dynamic data. In order to keep data traffic low, I thought it wise to get this data when the whole page is loaded and to pass it into the template initialization function.
In fact, I don't really know how to assign the store to the FilteringSelect.
Any help would be greatly appreciated.
Here's my code. I shorten it to the what I consider relevant parts so that it's easier to understand.
Grid Part:
var data_list = fetchPaymentProposalList.fetch();
/*create a new grid*/
var grid = new DataGrid({
id: 'grid',
store: store,
structure: layout
});
// store for FilteringSelect
var beneficiaryList = FetchBeneficiaryList.fetch();
var beneficiaryListStore = new Memory({
identifier : "id",
data : beneficiaryList
});
return {
// function to create dialog with form
instantiate:
function(idAppendTo) {
/*append the new grid to the div*/
grid.placeAt(idAppendTo);
/*Call startup() to render the grid*/
grid.startup();
grid.resize();
dojo.connect(grid, "onRowClick", grid, function(evt) {
var rowItem = this.getItem(evt.rowIndex);
var itemID = rowItem.id[0];
var store = this.store;
var paymentProposalForm = new TmpPaymentProposalForm();
paymentProposalForm._init(store.getValue(rowItem, "..."), ..., beneficiaryListStore);
});
}
};
The beneficiarylist comes as something like this:
return { 12: { id : 1, name : "ABC" }};
The FilteringSelect in the template looks like this:
<input data-dojo-type="dijit/form/FilteringSelect" name="recipient" id="recipient" value="" data-dojo-props="" data-dojo-attach-point="recipientNode" />
Template Init Code looks like this:
_init: function(..., beneficiaryListStore) {
this.recipientNode.set("labelAttr", "name");
this.recipientNode.set("searchAttr", "name");
// here should come the store assignment, I guess???
var dia = new Dialog({
content: this,
title: "ER" + incoming_invoice,
style: "width: 600px; height: 400px;"
});
dia.connect(dia, "hide", function(e){
dijit.byId(dia.attr("id")).destroyRecursive();
});
dia.show();
}
For anyone who's interested, here's my solution:
var beneficiaryList = FetchBeneficiaryList.fetch();
var beneficiaryData = {
identifier : "id",
items : []
};
for(var key in beneficiaryList)
{
if(beneficiaryList.hasOwnProperty(key))
{
beneficiaryData.items.push(lang.mixin({ id: key }, beneficiaryList[key]));
}
}
var beneficiaryListStore = new Memory({
identifier : "id",
data : beneficiaryData
});
That did the trick