Recursive properties set in Merchello product template's master - Parent must be set in order to recurse - umbraco7

I have some recursive properties set in the master page of my Umbraco website. These work fine for every page except my product template. I am using the Merchello ecommerce plugin.
On my product pages I get this error:
Parent must be set in order to recurse
The line of code causing this error is:
var pageTitle = Model.Content.GetPropertyValue("seoPageTitle", true);
I understand this is due to the product 'pages' not being part of the actual content tree in Umbraco. So somehow I need the product pages to have a parent to get these recursive properties working.
If I'm right with this, how do I set a parent?
Thanks very much in advance.

Related

Kentico 13 Xperience View Component displaying Page Type field data

If I had a page type called "MySite.TextBox" and it had two fields: "Title" and "Content" what all would be required for me to make a view component that pulls all page types from the site searching from "/" and looking down to have it appear as a list of items in any view, including the layout view, using something like <vc: text-box-list > in a view, such as the _layout
What files would I need to create aside from the TextBoxList view component?
I know I'll need to make a generated code file for the MySite.TextBox page type. But it's where I set up and establish the rules for outputting the list that things get fuzzy.
For instance if I wanted to establish rules like:
var textBoxList = DocumentHelper.GetDocuments("MySite.TextBox").TopN(5).Path("/", PathTypeEnum.Children).OrderByAscending("Title").ToList();
Would that be a part of the view component or something else?
I would just really really love to have an example. I hate that the Dancing Goat and Medio Clinic sites do not have one.
1. Follow the below to Create a widget -
https://docs.xperience.io/developing-websites/page-builder-development/developing-widgets
2. Retrieves pages of multiple page types from the '/' section of the content tree:
var pages = pageRetriever.RetrieveMultiple(multiDocumentQuery => multiDocumentQuery
.Path("/", PathTypeEnum.Children));
Reference:
https://docs.xperience.io/custom-development/working-with-pages-in-the-api#WorkingwithpagesintheAPI-Retrievingpagesonthelivesite
3. Retrieve Common data from multiple page types
var commondata=Pageretriver.RetriveMultiple(multiDocumentQuery=> multiDocumentQuery
.Types("PageType1","PageType2)
.WithCoupledColumns())
.Select(page=> new <desiredobject name>
{
fieldName=page.GetString("fieldName")
});
Reference
https://docs.xperience.io/custom-development/working-with-pages-in-the-api/reference-documentquery-methods

Link directly to a notebook page in a view

I have an view that extends the current project view, where we add multiple tabs (notebook pages) to show information from other parts of a project.
One of these pages is an overview page that summarizes what is under the other tabs, and I'd like to link the headlines for each section directly to each displayed page. I've currently solved this by using the index of each tab and calling bootstrap's .tab('show') method on the link within the tab:
$(".overview-link").click(function (e) {
e.preventDefault();
var sel = '.nav-tabs a:eq(' + $(this).data('tab-index') + ')';
$(sel).tab('show');
});
This works since I've attached a data-tab-index="<int>" to each header link in my widget code, but it's brittle - if someone adds a tab later, the current indices will be broken. Earlier I relied on the anchor on each tab, but that broke as well (and would probably break if a new notebook page were inserted as well).
Triggering a web client redirect / form link directly works, but I want to show a specific page in the view:
this.do_action({
type: 'ir.actions.act_window',
res_model: 'my.model.name',
res_id: 'my.object.id',
view_mode: 'form',
view_type: 'form',
views: [[false, 'form']],
target: 'current'
});
Is there any way to link / redirect the web client directly to a specific notebook page tab through the do_action method or similar on FormWidget?
If I understood well you want to select the tab from the JavaScript (jQuery) FormWidget taking into account that the id could change if anybody install another module that adds another tab
Solution 0
You can add a class to the page in the xml form view. You can use the id of the element selected by this class name in order to call the right anchor and select the right tab item. This should happen when the page is completely loaded:
<page class="nb_page_to_select">
$('a[href=#' + $('.nb_page_to_select').attr('id') + ']').click()
NOTE: As you have said the following paragrah I assume that you know where to run this instruction. The solution I suggest is independent of the index.
This works since I've attached a data-tab-index="<int>" to each
header link in my widget code, but it's brittle - if someone adds a
tab later, the current indices will be broken. Earlier I relied on the
anchor on each tab, but that broke as well (and would probably break
if a new notebook page were inserted as well).
Solution 1
When the page is loaded you can get the tab list DOM object like this:
var tablist = $('ul[role="tablist"]')
And then you can click on the specifict tab, selecing by the text inside the anchor. So you don't depend on the tab index:
tablist.find('a:contains("Other Information")').click()
I think if you have two tabs with the same text does not make any sense, so this should be sufficient.
Solution 2
Even if you want to be more specific you can add a class to the notebook to make sure you are in the correct notebook
<notebook class="nt_to_change">
Now you can use one of this expressions in order to select the tab list
var tablist = $('div.nt_to_change ul.nav-tabs[role="tablist"]')
// or
var tablist = $('div.nt_to_change ul[role="tablist"]')
Solution 3
If the contains selector doesn't convince you because it should be equal you can do this as well to compare and filter
tablist.find('a').filter(function() {
return $.trim($(this).text()) === "Other Information";
}).click();
Where "Other Information" is the string of the notebook page
I didn't tried the solution I'm giving to you, but if it doesn't work at least may be it makes you come up with some idea.
There's a parameter for XML elements named autofocus (for buttons and fields is default_focus and takes 1 or 0 as value). If you add autofocus="autofocus" to a page in XML, this page will be the displayed one when you open the view.
So, you can try to add this through JavaScript, when the user clicks on the respective link -which honestly, I don't know how to achieve that by now-. But you can add a distinctive context parameter to each link in XML, for example context="{'page_to_display': 'page x'}". When you click on the link, I hope these context keys will arrive to your JS method.
If not, you can also modify the fields_view_get method (here I wrote how to do that: Odoo - Hide button for specific user) to check if you get the context you've added to your links and add the autofocus parameter to the respective page.
As you said:
This works since I've attached a data-tab-index="" to each header
link in my widget code, but it's brittle - if someone adds a tab
later, the current indices will be broken.
I assume that your app allow multi-user interaction in realtime, so you have to integrate somewhere in your code, an update part function.
This function will trig if something has changed and cleanout the data to rebuilt the index in order to avoid that the current indices will be broken.

Wicket (1.6) stateless form resets paging

I've already tried to find anything about that problem but I guess I either was not sure how to shortly describe the problem to find a solution or nobody else had that before which I can't think of. Maybe my thinking is wrong, too.
I have a stateless wicket 1.6 form with an ajax supporting panel (WebMarkupContainer with output id). The panel holds a dataview with paging navigator. The dataview itself is filled by a DataProvider.
The panel shows some entries from the database and below that is the navigator. by clicking any page on the navigator, the panel is refreshed (ajax) and shows content from that page. The page itself is not re-rendered by the browser.
When I now leave the page by navigating to another internal page (so basically when leaving the dataview-panel-page in any way) to open a detail page or so and then return to that dataview-page the navigator is resetted (because it's stateless I guess). The navigator can't remember which page to show and begins at the top of the first page again.
The question is: How can I solve this? I would like to i.ex. navigate to page 2 and then temporary leave the page for another internal page. When returning I want to be on page 2, focussed on the record where I clicked the link to "details" before. This also happens when I just open a new page in a new Browser tab.
Thank you!
Here's some code:
final WebMarkupContainer gamesPanel = new AjaxContainer("gamesPanel");
final DataView<Game> dataView =
new GameDataView("gameOverview", targetCurrencyModel, searchTextModel, gameFilterModel,
new GameDataProvider(searchTextModel, gameFilterModel, targetCurrencyModel));
dataView.setItemsPerPage(ITEMS_PER_PAGE);
gamesPanel.add(dataView);
final XNPagingNavigator navigator = new XNPagingNavigator("navigator", dataView);
navigator.setOutputMarkupId(true);
add(navigator);
You guys can try what I mean: The page I'm talking about is http://www.xbox-now.de. Just navigate to page 2, then click on details and return to main page.
I think you might use History API to push a new state when you click on navigation bar. In the new URL for the state you can include a parameter that indicates the index of the current navigator page.
You can customize your AJAX link in order to perform this operations when user click on it.
For more details on History API see Updating address bar with new URL without hash or reloading the page
I solved this in the NoWicket framework by introducing a model aware page cache which reuses page instances when hashcode/equals matches in the page model. You can see the implementation in the GitHub repo, try this implementation of the IPageFactory wrapper as a starting point, but it is more code involved there, just check out the code, debug the example and navigate the code to understand it better in order to apply it to your application. See your use case in action by trying this data table example in the documentation website (which you can also debug locally): http://invesdwin.de/nowicket/ajaxdatatable
Try changing the paging index, navigate to a different page and navigate back to the data table example page. You will still see the paging index that you left there.
Thank you guys for your replies. I've done it now another way. Used the base code from here and modified it in some ways. Added some nice css AttributeModifiers to indicate the actual page:
item.add(new AttributeModifier("class", new PageLinkCssModel(pageable, pageIndex, "active")));
Then I modified some code to add or reset the page parameter, that it's 1) used only once and 2) keeps all the actual page parameters which were there before adding own ones. So I am just appending the page number now. This way I can keep my initially mount path like www.foo.bar/path/path/path. Complete URL would now look like: www.foo.bar/path/path?page=123.
To pass my entered page (i.e. page=5) to the data provider I just had to override the providers iterator. It should start with the page I entered. Due to the ugly generated navigator URLs (which are extremly bad for SEO) I now have nice looking urls which are working independently what wasn't possible before. And that's also the reason why I could not get back to the correct page. The navigator URL was not lookup-able by wicket.
new DataView<GamePrice>("gamePriceOverview", new GameDetailDataProvider(gameId, targetRegion) {
#Override
public Iterator<GamePrice> iterator(final long first, final long count) {
return super.iterator(ITEMS_PER_PAGE * getCurrentPage(), count);
}
getCurrentPage() comes from the base template and gets the actual page number entered (if one is entered):
public long getCurrentPage() {
// -1 weil zero based
return getRequest().getQueryParameters().getParameterValue("page").toString() != null
? (getRequest().getQueryParameters().getParameterValue("page").toLong() - 1)
: 0;
}
So instead of having ugly SEO-unfriendly URLs which are also not compatible to work independant (directly enter the generated url) I now have the same URL I expect with an added page-parameter.
URL now would looks like:
http://localhost:8080/game/4249/de/doom-preorder?page=2
URL before was:
localhost:8080/game/4249/DE/doom-preorder?0-1.ILinkListener-gamePrices-navigator-navigation-2-pageLink
If I now go back from the detail page to the main index with active "Bookmarkable-Navigator", I correctly come back to the page and position where I left it (because of bookmarkable page links).
That's how I achieved this problem with a nice bonus: User- and SEO-friendly URLs.

Including Joomla! 3 module in custom position on custom component

I've seen alot of examples of how to include modules on a custom joomla! component using JModuleHelper::getModules, however, when trying to include modules in a custom position, the array come back empty. Here's my code in my component's template:
<?php
jimport('joomla.application.module.helper');
$modules = JModuleHelper::getModules('comwhcustomer');
foreach ($modules as $module){
echo JModuleHelper::renderModule($module);
}
?>
You'll notice the position I'm passing the getModules function is comwhcustomer. This code is returning a blank array. If I pass "footer", I do successfully get the module in the footer position.
I'm using an adapted protostar tempalte and I have added the comwhcustomer position to the xml definition file for the template. I've created the module in module manager and in the position filed, I've selected the "comwhcustomer" position that shows up in the dropdown. On the modules manager page, I see the module listed in the position selected (comwhcustomer). I've confirmed in the database table #__modules that the position is saved correctly.
However, the array is still coming back empty on the getModules call. What am I missing?
Joomla version 3.4.1
Local environment
Windows IIS
PHP 5.4.24
MySQL db
PS - As an alternative, I have sucessfully loaded the module with JModuleHelper::getModule() however, none of the attributes I define in the module manager come over, because they're not supposed to. I'd like to use the method mentioned above so I can control the module behavior from the manager rather than attributes in the code, because this position will be used in multiple views of this component.
This is my first time posting to SO. I do appreciate the support :-)
itoctopus, you were exactly right! The module itself was not assigned to any pages, that's the piece I was not taking into consideration! Thank you so much for your help! I set it to display on all pages and it worked!
Of course, it doesn't show up on all the other pages because they do not contain a position called "comwhcustomer" so it is exactly what I was looking for!

How to force the Drupal form to clear previous results

Recently im working on a project and im trying to generate form elements with the help of ajax technology (implementing a form with codes). the situation is that the user should be able to select from a list of options and then due to his select another list of options should be appeared, then due to his/her select from the second sets of options he/she should see the third series of options. now the problem is that when the user tries to change the first option in the first set, the second option will be regenerate but the third one still sticks on the page. I was trying to use the form_sate['rebuild'] = TRUE
but it did not work and all form elements disappeared. can any one help me to see which code should be implemented and where it should be used?
Without any code it's almost impossible to help, except to say check out the examples modules, specifically the ajax_example module.
The basic principle is that you need a <div> container surrounding your 2nd and 3rd select elements, which will be replaced by the #ajax set on the first element. Then you need another container inside that one surrounding only the 3rd select element, which will be replaced by the #ajax set on the 2nd select element.
Hope that helps.
well.. the form page may contains previous values because of $_POST fields variables..
for example if I want to display clear "add" form on POST submit,
I do this tric to clear drupal previous form values via ajax:
<?php
// AJAX POST handler...
....
$my_form = drupal_render(drupal_get_form("the_form", ...));
$errors = form_get_errors();
if (!$errors) {
// re-render clean form, unset your POST fields....
unset($_POST['link_path']);
unset($_POST['link_title']);
unset($_POST['parent']);
unset($_POST['weight']);
$my_form = drupal_render(drupal_get_form("the_form", ...));
}
?>

Resources