I'm using EPiServer version 11 and I have requirement that when property of type linkItemCollection is rendered using PropertyFor() method, I need to add some custom attribute ( based on condition if target is blank ) to generated hyperlink.
#Html.PropertyFor(x => x.Layout.LinksCollection)
I have idea of creating a custom view under DisplayTemplates in view and adding new view. My query is how can i get default template for linkItemCollection to get it started ?
The easy option would be to o it yourself and not worry about the Property for, the only slight issue is that you may not get inline editing to work.
https://www.jondjones.com/learn-episerver-cms/episerver-developers-tutorials/episerver-properties/how-to-display-a-list-of-links-in-episerver/
To go with your route
[UIHint("MyView")]
[Display(
GroupName = SystemTabNames.Settings,
Order = 100)]
public virtual LinkItemCollection MyProperty{ get; set; }
In Views/Shared/DisplayTemplates add a template MyView.cshtml
Instead of using the PropertyFor you could take full control of the rending yourself.
// FullRefreshPropertiesMetaData asks on-page edit to reload the page
// to run the following custom rendering again after the value has changed.
#Html.FullRefreshPropertiesMetaData(new []{ "RelatedContentLinks" })
// EditAttributes enables on page-edit when you have custom rendering.
<p #Html.EditAttributes(m => m.CurrentPage.RelatedContentLinks) >
#if (Model.CurrentPage.RelatedContentLinks != null)
{
<span>See also:</span>
foreach (LinkItem item in Model.CurrentPage.RelatedContentLinks)
{
#item.Text }
}
</p>
Taken from the EPi documentation
Thanks for your input on this.
I managed to resolve this as below.
public static MvcHtmlString LinkItemCollectionFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
MvcHtmlString result = PropertyExtensions.PropertyFor(html, expression);
return MvcHtmlString.Create(result.ToString().Replace("target=\"_blank\"", "target=\"_blank\" rel=\"noopener noreferrer\""));
}
Hope, it helps someone.
Related
I am playing around with AngularJS 2.0
My very simple scenario consists of a select box that is bound to a property of component attribute, like this:
<select [(ngModel)]="zeitraum" [value]="zeitraum" (change)="calculate()">
<option>....</option>
</select>
The component class looks like this:
export class MyComponent
{
constructor
(
public zeitraum: number = 10,
public result: number = 0
)
{
}
public calculate()
{
this.result = this.zeitraum * 5;
}
}
So, I have a select box with a couple of options and I want the following behaviour: when a new option is selected, call the calculate() method which simply multiplies 'zeitraum' by 5 and then sets the value of 'result' which is then displayed on the page.
<h1>Result: {{result}}</h1>
The problem is as follows: The calculate method is called but it uses the OLD value of 'zeitraum' (that is, the value before a new option was selected).
I wonder which event to use here. I tried a workaround by using (mouseleave) and (mousemove) events and that seemed to work but it's a really dirty hack so there should be a more elegant solution.
Either I am using the wrong event or I got something else wrong with my Angular code.
Has anybody a suggestion? Thanks a lot in advance.
You should be able to do it like this:
<select [(ngModel)]="zeitraum" (change)="calculate($event.target.value)">
<option>....</option>
</select>
public calculate(zeitraum)
{
this.result = zeitraum * 5;
}
In page edit mode I want to show a read-only text that is based on a page property value. The text could for example be "A content review reminder email will be sent 2015-10-10", where the date is based on the page published date + six months (a value that will be configurable and therefore can change anytime). So far I've tried to accomplish something like this by adding another property on the page.
I've added the property CurrentReviewReminderDate to an InformationPage class we use. In page edit mode the property name is shown, but it doesn't have a value. How do I do to show the value in page edit mode (preferably as a label)?
[CultureSpecific]
[Display(
Name = "Review reminder date",
Description = "On this date a reminder will be sent to the selected mail to remember to verify page content",
Order = 110)]
[Editable(false)]
public virtual string CurrentReviewReminderDate
{
get
{
var daysUntilFirstLevelReminder =
int.Parse(WebConfigurationManager.AppSettings["PageReviewReminder_DaysUntilFirstLevelReminder"]);
if (CheckPublishedStatus(PagePublishedStatus.Published))
{
return StartPublish.AddDays(daysUntilFirstLevelReminder).ToString();
}
return "";
}
set
{
this.SetPropertyValue(p => p.CurrentReviewReminderDate, value);
}
}
EPiServer internally uses the GetPropertyValue method (i.e. the opposite of SetPropertyValue) when retrieving content for the UI.
This makes sense, otherwise your "made-up" value would be stored as the real value whenever the content is saved. This would make fall-back values etc impossible to implement.
So, this is by-design (and quite wisely so) in EPiServer. :)
However, you can customize how properties work by:
Using custom editors by applying UI hints
Modifying property metadata (for example, to display a generated value as a watermark in a textbox without interfering with the actual value being saved)
I could be misunderstanding what you're trying to do, but off the top of my head it looks like a custom editor could be a viable option for your use case?
Another solution would be to hook into the LoadedPage-event and add the value from there. This might not be the best way performance-wise since you need to do a CreateWritableClone, but depending on the site it might not matter.
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class EventInitialization : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
ServiceLocator.Current.GetInstance<IContentEvents>().LoadedContent += eventRegistry_LoadedContent;
}
void eventRegistry_LoadedContent(object sender, ContentEventArgs e)
{
var p = e.Content as EventPage;
if (p != null)
{
p = p.CreateWritableClone() as EventPage;
p.EventDate = p.StartPublish.AddDays(10);
e.Content = p;
}
}
}
In MVC, there's a ViewSwitcher, and you can add _Layout, _Layout.mobile; MyView and optional MyView.mobile
What's the best way to accomplish this in ServiceStack razor view? Thanks
ServiceStack doesn't implicitly switch layouts at runtime, instead the preferred layout needs to be explicitly set. ServiceStack's RazorRockstars Demo website explains how to dynamically switch views, i.e:
Change Views and Layout templates at runtime
The above convention is overrideable where you can change both what View and Layout Template is used at runtime by returning your Response inside a decorated HttpResult:
return new HttpResult(dto) {
View = {viewName},
Template = {layoutName},
};
This is useful whenever you want to display the same page in specialized Mobile and Print Preview website templates. You can also let the client change what View and Template gets used by attributing your service with the ClientCanSwapTemplates Request Filter Attribute:
[ClientCanSwapTemplates]
public class RockstarsService : RestServiceBase { ... }
Which itself is a very simple implementation that also shows you can you can swap the View or Template used inside a Request Filter:
public class ClientCanSwapTemplatesAttribute : RequestFilterAttribute
{
public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
{
req.Items["View"] = req.GetParam("View");
req.Items["Template"] = req.GetParam("Template");
}
}
This attribute allows the client to change what View gets used with the View and Template QueryString or FormData Request Params. A live example of this feature is used to change the /rockstars page:
/rockstars?View=AngularJS
/rockstars?Template=SimpleLayout
/rockstars?View=AngularJS&Template=SimpleLayout
Changing Layout used from inside a view
You can even change the layout used by setting the Layout property from inside a Razor View, e.g:
#inherits ViewPage<Response>
#{
Layout = IsMobileRequest(base.Request) ? "_LayoutMobile" : "_Layout";
}
We are using PageTypeBuilder to define our PageTypes, on one page we have a property which represents a Link item collection as below:
[PageTypeProperty(Type = typeof(PropertyLinkCollection), HelpText = "Test links.", EditCaption = "Test links", SortOrder = 11)]
public virtual LinkItemCollection PageLinks { get; set; }
We can populate this in CMS editor mode with links, save and publish without any errors. We then have a user control that inherits from EPiServer.UserControlBase and grabs the LinkItemCollection property using the below code and binds it to a repeater:
var links = currentPage.Property["PageLinks"].Value as LinkItemCollection;
if (links != null)
{
linkRepeater.DataSource = links;
linkRepeater.DataBind();
}
If I view the page when logged in as a CMS editor this page works fine and the links parameter is populated correctly, however if I view the page as a normal user and not logged in the links variable is always null (although when I'm debugging I can see the currentPage.Property["PageLinks"] is present, and the type is LinkCollection, its just that the Value is null
Is there something I need to configure here, permissions on a specific page type?
The problem is most likely one of the pages in the LinkItemCollection not being accessible by outside visitors. Try accessing the links in the collection as an outside visitor and remove any of the links that are in fact locked from outside view.
I have implemented Linq-To-Sql..
Add necessary table in it...
after that linq class will automatically set property for field..
I implemented one class using ObservableCollection class.. and pass datacontextclass object in its constructor...
so after getting all data how to filter it?
public class BindBookIssueDetails : ObservableCollection
{
public BindBookIssueDetails(DataClasses1DataContext dataDC)
{
foreach (Resource_Allocation_View res in dataDC.Resource_Allocation_Views)
{
this.Add(res);
}
}
}
private BindBookIssueDetails bResource;
bResource = new BindBookIssueDetails(db);
_cmbResource.ItemSource=bResource;
Please Help me.
You can use CollectionViewSource and filter it. So that it affect only at the View(.XAML) side
ICollectionView collectionView = CollectionViewSource.GetDefaultView(bResource);
collectionView.Filter = new Predicate<object>(YourFilterFunction);
Check out this blog for more details. http://bea.stollnitz.com/blog/?p=31
I tried to use #Jobi's solution but for some reason I got an exception trying to fire FilterFunction.
So I used a slightly different approach. I cast CollectionViewSource's DefaultView to a BindingListCollectionView
myVS=(BindingListCollectionView)CollectionViewSource.GetDefaultView(sourceofdata);
and now I can construct an SQL-like filter string and apply it like that:
myVS.CustomFilter=myfilterstring;
I will still try to resolve my problem (I presume #Jobi's solution is more flexible).