Sitecore Set the Number of Components - sitecore

Is it possible to set the number of components in placeholder?
We can add as many as components in placeholder by using "Add to here" in gray box even the component has been already added.
I'd like to say that
In plcaceholder named 'bodyArea', you can set only one component in 'bodyArea' placeholder and you will not add any other component additionally.
Is there anyway how to do this??

There could be many ways, but this is what I used before.
// Check the number of renderings in placeholder
public static bool numberOfRenderings(string placeholderName)
{
bool rendering = true;
var renderingReferences = Sitecore.Context.Item.Visualization.GetRenderings(Sitecore.Context.Device, true);
int renderingsInPlaceholder = renderingReferences.Where(r => r.Placeholder.EndsWith('/' + placeholderName, StringComparison.OrdinalIgnoreCase)).Count();
if (renderingsInPlaceholder > 1)
{
return rendering = false;
}
return rendering;
}
In View.cshtml
if (#yourObject.numberOfRenderings("your-placeholder-key")) {
#Html.Sitecore().Placeholder("your-placeholder-key")
}
else
{
#Html.Raw("<div>Only one rendering item is available in this placeholder.</div>")
}

here is a blog where is describing how to restrict number of allowed controls :
http://www.newguid.net/sitecore/2014/restricting-the-number-of-components-in-the-sitecore-page-editor/
Other solution is using rules :
http://dotnetmafia.com/blogs/kevin/archive/2013/07/10/placeholder-settings-rules.aspx

Related

Edit method Set parameter is not setting to true in check box control

I am using edit method on a form Check box control in a Grid and data source is a view. The parameter in _set boolean is not setting to true when we clicked on the check box. The code in the edit method is as follows.
edit NoYes markNow(
boolean _set,
VendInvoiceProdReceiptNotInvoicedView _vendInvoiceProdReceiptNotInvoicedViewLocal,
NoYes _markNow)
{
if (_set)
{
if (_markNow)
{
matchedReceipts.insert(_vendInvoiceProdReceiptNotInvoicedViewLocal.VendPackingSlipJourRecId, _vendInvoiceProdReceiptNotInvoicedViewLocal.PackingSlipId);
}
else
{
if (matchedReceipts.exists(_vendInvoiceProdReceiptNotInvoicedViewLocal.VendPackingSlipJourRecId))
{
matchedReceipts.remove(_vendInvoiceProdReceiptNotInvoicedViewLocal.VendPackingSlipJourRecId);
}
}
this.refresh();
}
return matchedReceipts.exists(_vendInvoiceProdReceiptNotInvoicedViewLocal.VendPackingSlipJourRecId) ? NoYes::Yes : NoYes::No;
}
Could you please help me with this.
Edit methods cannot be used on top of Views as data source, Use regular table as data source.

First Visible Row in Codenameone

I tried this code to get the first visible row in a scrolling Table inside a BorderLayout.CENTER, but it didn't work, seems the points returned do not reflect the visible cells, unless I am missing a sort of calculation,
thank you for your insights,
#Override
protected void onScrollY(int scrollY) {
super.onScrollY(scrollY); //To change body of generated methods, choose Tools | Templates.
Component c=getComponentAt(50, scrollY);
if (c instanceof Table){
System.err.println("table "+getWidth()+" "+getHeight()+" s "+scrollY);
return;
}
Button b=(Button) c;
System.err.println("c: "+b.getText());
}
getComponentAt(x,y) takes absolute (screen) coordinates. The scrollY value is a relative coordinate in that container.
So what you want is something like:
Component c = getComponentAt(getAbsoluteX()+50, getAbsoluteY() + scrollY)
Also worth nothing that getComponentAt(x,y) will only return components that are focusable or have been set to grab pointer events. If you just want to find the first paintable immediate child of this container, and you're using a BoxLayout.Y_AXIS layout, then you might be better to just iterate through the children until you find one where y is at least the scrollY.
e.g.
Component c = null;
for (Component child : this) {
if (child.getY() + child.getHeight() > scrollY) {
c = child;
break;
}
}
....

Personalization in SItecore

I want to display some different sublayout if user has visit some page more than 2 times so I want to use this rules "where the visit no. compares to number" but I do not have idea how I can use it? I tried to add this rule and replace "number" to 2 but it is not working.
As Marek said this is not possible with the condition you are using. However you could adjust the Rule condition to achieve this by looking at the VisitPageIndex for the page.
public class ContactVisitPageIndexCondition<T> : OperatorCondition<T> where T : RuleContext
{
public int No
{
get;
set;
}
public ID PageGUID
{
get;
set;
}
public ContactVisitPageIndexCondition()
{
}
protected override bool Execute(T ruleContext)
{
Assert.ArgumentNotNull(ruleContext, "ruleContext");
Assert.IsNotNull(Tracker.Current, "Tracker.Current is not initialized");
Assert.IsNotNull(Tracker.Current.Session, "Tracker.Current.Session is not initialized");
Assert.IsNotNull(Tracker.Current.Session.Interaction, "Tracker.Current.Session.Interaction is not initialized");
int contactVisitPageIndex = Tracker.Current.Session.Interaction.Pages.SingleOrDefault(p => p.Item.Id == PageGUID).VisitPageIndex;
switch (base.GetOperator())
{
case ConditionOperator.Equal:
{
return contactVisitPageIndex == this.No;
}
case ConditionOperator.GreaterThanOrEqual:
{
return contactVisitPageIndex >= this.No;
}
case ConditionOperator.GreaterThan:
{
return contactVisitPageIndex > this.No;
}
case ConditionOperator.LessThanOrEqual:
{
return contactVisitPageIndex <= this.No;
}
case ConditionOperator.LessThan:
{
return contactVisitPageIndex < this.No;
}
case ConditionOperator.NotEqual:
{
return contactVisitPageIndex != this.No;
}
}
return false;
}
}
As Marek Musielak said, Where the visit no. compares to .. related to visit to the site and not an individual page.
I had a look in the Sitecore API, its Tracker namespace and the closest property I can find to individual page view count is VisitPageIndex but decompiling the code and checking in MongoDB shows that is just the index of the page was viewed for that visit to the site so this won't work for you.
Looking in MongoDB there are no properties to store page views but it does store the Pages viewed for Interactions so you could write a custom rule counting the number of times that page is in the Pages array
e.g.
int pageViewed = Tracker.Current.Session.Interaction.Pages.Count(p => p.Item.Id.Equals(yourPageId))
An alternative if you don't want to write custom is to change your approach a bit inline with how Sitecore personalisation scan work out of the box.
You'll want to use or create profile keys in the Marketing Centre e.g. 'Brand Aware'. Assign your new profile key to the page in question and assign it a score e.g. 10. This means that each time a user visits this page they will be given a 10 points in 'Brand Aware'.
Now for the personalisation bit. Create a new personalisation rule on the existing sublayout using 'where the value of the specific profile key compares to specific value' set it to hide if the score is greater than or equal to 20. Create another to display your new sublayout if the value is greater than or equal to 20.
I've wrote a blog about this if you need more info

Sitecore dictionary items Editable via page editor

I am trying to implement Sitecore Dictionary items to be edited via PageEditor.
This is my approach.. Just need your thoughts and suggestions.
To make it simple and not to mess up with the pipelines, here is a simple way of what I am doing.
Normally you do a sitecore translate for example,
#Sitecore.Globalization.Translate.Text("SomeKey")
You can encapsulate the Translate to a custom class which might look like
public static class CustomTranslate
{
public static string Text(string key)
{
if (Sitecore.Context.PageMode.IsPageEditorEditing)
{
string val = String.Empty;
Item currentItem = Context.Database.GetItem(ResourcesController.ItemLookUp()[key]);
if (currentItem != null)
{
val = FieldRenderer.Render(currentItem, "Phrase");
}
return val;
}
else
return Sitecore.Globalization.Translate.Text(key);
}
}
The CustomTranslate.Text returns a FieldRenderer in PageEdit mode else returns the Sitecore.Globalization.Translate.Text
Then in your code you can refer the translations as
#CustomTranslate.Text("SomeKey")
The Lookup can be a dictionary of Key and Item ID as shown in below code,
public static class ResourceController
{
public static Dictionary ItemLookUp()
{
///get dictionary path..etc.. code not included
//read all sitecore dictionary Items
Sitecore.Data.Items.Item[] items =
Sitecore.Context.Database.SelectItems("fast:" + dictionaryPath +
"//*[##templateid='{6D1CD897-1936-4A3A-A511-289A94C2A7B1}']");
//build a Dictionary<string,string> using sitecore item key and Guid.
items.All(y => { resourceDictionary.Add(y["Key"], y.ID.Guid.ToString()); return true;}
// Key,Guid dictionary
return resourceDictionary;
}
}
A Simpler and much easier approach ! Thoughts, Comments ?

Grouping Controls

I'm using C++ Builder 5. Is there a way to group a disparate set of controls so that by simply calling, for instance, myGroup.Enabled = false; will set all group of controls enabled property to false? I can't use a GroupBox since the controls (labels, checkboxes, etc) are on different TabPages.
The reason I ask is so I don't have to call each control's enabled property explicitly and can do it with one simple call.
If not, how can I create a custom Control class to do this?
Since the controls you want to group are not in the same container, then I suggest using a TAction (look at the TActionList component). All TControl descendants have a public (sometimes even published) Action property. You can have the same TAction object assigned to multiple controls at the same time. Enabling/disabling the TAction (or updating any of its other properties) will automatically update all associated controls accordingly.
You could use the Tag property of the controls and create your own grouping.
void TForm1::SetControlState(TWinControl *WinCtrl, const bool IsEnabled, const int TagValue)
{
// set the enabled property for each control with matching TagValue
for (int Index = 0; Index < WinCtrl->ControlCount; ++Index)
{
if (WinCtrl->Controls[Index]->Tag == TagValue)
{
WinCtrl->Controls[Index]->Enabled = IsEnabled;
}
// set child controls
if (WinCtrl->Controls[Index]->InheritsFrom(__classid(TWinControl)))
{
TWinControl *TempWinCtrl;
TempWinCtrl = static_cast<TWinControl *>(WinCtrl->Controls[Index]);
SetControlState(TempWinCtrl, IsEnabled, TagValue);
}
} // end for
}
Alternatively, If you want to enable/disable all controls in one go.
void TForm1::SetControlState(TWinControl *WinCtrl, const bool IsEnabled)
{
// set the enabled property for each control with parent TabSheet
for (int Index = 0; Index < WinCtrl->ControlCount; ++Index)
{
WinCtrl->Controls[Index]->Enabled = IsEnabled;
// disable child controls
if (WinCtrl->Controls[Index]->InheritsFrom(__classid(TWinControl)))
{
TWinControl *TempWinCtrl;
TempWinCtrl = static_cast<TWinControl *>(WinCtrl->Controls[Index]);
SetControlState(TempWinCtrl, IsEnabled);
}
} // end for
}
Examples:
// disable all controls on the form
SetControlState(Form1, false);
// disable all controls on a tabsheet
SetControlState(TabSheet1, false);
NOTE: The above code has been tested with C++Builder 2007