Access top level content item from a widget

Topics: Writing modules
Jul 28, 2011 at 4:19 PM
Edited Jul 28, 2011 at 4:20 PM

I have a ninja widget that I have displayed on all of my pages.  There are certain settings for this widget that I want to be page specific so I can't just add them to my widget itself as those settings would be global to every page that this widget is plan was to create a NinjaSettingsPart that contained some fields for those settings and attach that to the Page content type. 

Then in the driver for the NinjaWidget, I could access the NinjaSettingsPart that was attached to the page and interrogate some of those settings and respond appropriately.

I have it setup, and now when I step through my code in the driver of my  NinjaWidget:

part.ContentItem.ContentType is NinjaWidget...this makes sense, though at first I was expecting part.ContentItem.ContentType to be "Page."  I can't seem to find a way to get back to the original content item for the page itself.  Is there a way to get access to that so that once I have the page, I can access the parts that are tied to the page and therefore interrogate the NinjaSettingsPart?

Jul 29, 2011 at 12:15 AM

You can send shapes to top-level zones without having to be a widget:

Jul 29, 2011 at 2:36 PM

I don't think I'm explaining myself correctly, because I don't think that link accomplishes what I want...

Basically from my widget, I want to access values from a content part that exists on the same page that the widget exists on:

Page contains:

Widget A
ContentPart A

From WidgetA's driver, I want to be able to say: if(ContentPartA.SomeField == "foo") { /*do something*/ }

Jul 29, 2011 at 8:05 PM

Right, I had understood it that way, but you can't do that, because there is no reliable "the page". This is why I was suggesting instead that it's the content item that pushes the shape to a zone isntead of having a widget pull data from a hypothetical current content item.

If you do have a part *and* a widget, well, that seems a little clunkier than necessary, but you could push the data that you need from the part as an expando on the Layout, which both have access to through the work context.

Jul 29, 2011 at 8:28 PM

Alright, let me read back through your post again and see if I understand what you're saying a little better. Thanks...

Aug 1, 2011 at 6:45 PM

I think I understand, but if you could just clarify some things...

1. ) Is it true then that I no longer need to set the ninja widget as a widget in my migration? I can remove that line and just call it a NinjaPart?


2.) I assume I'll just have to attach this NinjaPart to a page or article or whatever content item I want it to show for and the driver will take care of sending it to the correct zone as long as I set the code up the way you mention in that blog post.

3.) Once I do get it to render into the correct zone (RightAside), I'll still need to access the other part (my NinjaSettingsPart) that exists on the content item so that I can read out some of the settings and react appropriately in the NinjaPart.  Will I just be able to access it via

var settingsPart = part.ContentItem.As<NinjaSettingsPart>()


Aug 1, 2011 at 6:49 PM

1. yes

2. yes

3. yes

Aug 1, 2011 at 7:09 PM

Regarding placement with this...I got it to show on the RightAside zone, but it was also displaying in my Content section of my page...this is because my placement had it set to Content:1.  When I remove the placement it doesn't show anywhere.  When I add the placement back and change content to RightAside, it displays.  That works, but it seems like I'm basically hardcoding the zone that this should be placed in by doing it this way.  Is there a more dynamic way to make this happen? If a user uses this module, they might not have a RightAside.  With a widget, they can customize it in the admin of the CMS, but here, they'd have to edit the placement file and the driver to put it in the correct zone.

Aug 1, 2011 at 7:17 PM

mmh. Yes, that is super-weird. A shape should be able to be in only one place at a time, which makes me think that somehow you have two shapes. I had to do nothing of the sort in Buy From Amazon. You might want to compare the code.

Aug 1, 2011 at 7:36 PM

OK, I'll compare the two. In the meantime, what should the placement be using this method?

Aug 1, 2011 at 7:43 PM

It shouldn't matter. I don't think I had placement in my own module.

Aug 1, 2011 at 7:56 PM

Hmm, without placement, it doesn't show up at all.

Aug 1, 2011 at 8:32 PM

I have to say that have NinjaWidget is quite cool!! like it!

Aug 1, 2011 at 8:58 PM

@Bertrand, it seems you do have a placement entry in your module:

  <Place Parts_Settings_AssociateAccountSettingsPart="Content:after"/>
  <Place Parts_BuyFromAmazon="Content:after" Parts_BuyFromAmazon_Edit="Content:1.5"/>
  <Place Fields_Common_Text_Edit__Author="Content:1.1" Fields_Common_Text__Author="Content:1.1"/>
Aug 1, 2011 at 9:45 PM

Regardless, it looks like it had something to do with the delayed delegate I was using:  The previous syntax used to be:

protected override DriverResult Display(RelatedContentPart part, string displayType, dynamic shapeHelper)
  return ContentShape("Parts_RelatedContent",
       () =>
  ... _work.GetContext().Layout.Zones["RightAside"].Add(shape, "1"); return shape; } ); }
So the first return was rendering the contentshape, and then it was getting into the delegate and adding the shape to the RightAside zone...

Aug 1, 2011 at 10:54 PM

Ah yes, that makes sense. Were you able to make it work?

Aug 2, 2011 at 12:27 PM

So far, yes, no problems. This is a really cool way to solve the problem.  It seems like your Amazon part and my scenario have pretty much the same need, so it was cool to be able to apply the same solution.