Does anyone know if it's possible to read Page Template Metadata from within a Razor TBB? I'm implementing a design that's been built using the 960 grid system and to keep my CT's reusable I was hoping to be able to do something like:
<div class="#Page.Template.Metadata.content_grid">
</div>
Unfortunately this throws a null reference exception.
Is what I'm attempting possible or do I need to write a custom TBB to add this information to the package?
After heading over to Alex's blog to ask the question, I see that he's already answered it for someone else:
Regarding getting Template Metadata out… unfortunately I have not
created a wrapper yet for the Template itself, the #Template that is
exposed right now is just the
Tridion.ContentManager.CommunicationManagement.Template one, which
means for now you’ll have to get template fields out the old fashioned
way:
#{ Tridion.ContentManager.ContentManagement.Fields.ItemFields
templateFields = new
ContentManager.ContentManagement.Fields.ItemFields(Template.Metadata,
Template.MetadataSchema); }
I’ve added this on my To Do list now though, so you’ll be sure to see
a convenience wrapper that will allow you to do
#Template.MetaData.YourField in version 1.3.
I was able to get this for Component Template Metadata using the following code:
#foreach (var cp in ComponentPresentations) {
#if (cp.Template.Metadata != null && cp.Template.Metadata["position"] != null){
#Debug(string.Format("The Component Template position is {0}", cp.Template.Metadata["position"].InnerText))
#if (cp.Template.Metadata["position"].InnerText.ToLower().Equals("main")){
#cp.RenderComponentPresentation()
}
}
}
Therefore, I think that you should be able to use something similar to the following:
#if (Page.Template.Metadata != null && Page.Template.Metadata["content_grid"] != null){
#Debug(string.Format("The content_grid value is {0}", Page.Template.Metadata["content_grid"].InnerText))
<div class="#Page.Template.Metadata["content_grid"].InnerText">
</div>
}
Please note the .InnerText and not .Value as the content_grid is returned as xml. In my code 'position' was just a string. I guess that this may be different if you're using taxonomy.
Thanks,
Jonathan
P.S. I am using version 1.2 of the Razor Mediator
Related
I am completely new to the the Shopware (6) community and I am still learning how to code in Symfony and Vue.js.
After trying some how to's in the developer wiki, I wanted to try some coding by myself.
I would like to combine https://docs.shopware.com/en/shopware-platform-dev-en/how-to/add-admin-new-field and https://docs.shopware.com/en/shopware-platform-dev-en/how-to/new-tab-admin?category=shopware-platform-dev-en/how-to into one functionallity (Product tabs with custom admin fields).
However, when I use the v-model attribute into an input field, the complete tab will turn white and the following error is outputted in the console: product is not defined.
My guess is that the model needs to be imported into the module (I can't find this anywhere into the docs).
Can someone tell me what I have to do to make this work? My current source code can be found here: https://github.com/Millerdigital-matthew/miller-product-upsells
As I understand, you need to change your index.js as follows:
const { Component } = Shopware;
const { mapState } = Component.getComponentHelper();
Component.register('...', {
computed: {
...mapState('swProductDetail', [
'product'
]),
}
});
I looked into your current code.
In your extension you try to bind
v-model="product.manufacturerId"
But in the block you are extending, there is no product defined.
So the solution to this problem, is to define product on your
view/sw-product-detail-upsells
I want to give my users the possibility to create document templates (contracts, emails, etc.)
The best option I figured out would be to store these document templates in mongo (maybe I'm wrong...)
I've been searching for a couple of hours now but I can't figure out how to render these document template with their data context.
Example:
Template stored in Mongo: "Dear {{firstname}}"
data context: {firstname: "Tom"}
On Tom's website, He should read: "Dear Tom"
How can I do this?
EDIT
After some researches, I discovered a package called spacebars-compiler that brings the option to compile to the client:
meteor add spacebars-compiler
I then tried something like this:
Template.doctypesList.rendered = ->
content = "<div>" + this.data.content + "</div>"
template = Spacebars.compile content
rendered = UI.dynamic(template,{name:"nicolas"})
UI.insert(rendered, $(this).closest(".widget-body"))
but it doesn't work.
the template gets compiled but then, I don't know how to interpret it with its data context and to send it back to the web page.
EDIT 2
I'm getting closer thanks to Tom.
This is what I did:
Template.doctypesList.rendered = ->
content = this.data.content
console.log content
templateName = "template_#{this.data._id}"
Template.__define__(templateName, () -> content)
rendered = UI.renderWithData(eval("Template.#{templateName}"),{name:"nicolas"})
UI.insert(rendered, $("#content_" + this.data._id).get(0))
This works excepted the fact that the name is not injected into the template. UI.renderWithData renders the template but without the data context...
The thing your are missing is the call to (undocumented!) Template.__define__ which requires the template name (pick something unique and clever) as the first argument and the render function which you get from your space bars compiler. When it is done you can use {{> UI.dynamic}} as #Slava suggested.
There is also another way to do it, by using UI.Component API, but I guess it's pretty unstable at the moment, so maybe I will skip this, at least for now.
Use UI.dynamic: https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
It is fairly new and didn't make its way to docs for some reason.
There are few ways to achieve what you want, but I would do it like this:
You're probably already using underscore.js, if not Meteor has core package for it.
You could use underscore templates (http://underscorejs.org/#template) like this:
var templateString = 'Dear <%= firstname %>'
and later compile it using
_.template(templateString, {firstname: "Tom"})
to get Dear Tom.
Of course you can store templateString in MongoDB in the meantime.
You can set delimiters to whatever you want, <%= %> is just the default.
Compiled template is essentially htmljs notation Meteor uses (or so I suppose) and it uses Template.template_name.lookup to render correct data. Check in console if Template.template_name.lookup("data_helper")() returns the correct data.
I recently had to solve this exact (or similar) problem of compiling templates client side. You need to make sure the order of things is like this:
Compiled template is present on client
Template data is present (verify with Template.template_name.lookup("data_name")() )
Render the template on page now
To compile the template, as #apendua have suggested, use (this is how I use it and it works for me)
Template.__define__(name, eval(Spacebars.compile(
newHtml, {
isTemplate: true,
sourceName: 'Template "' + name + '"'
}
)));
After this you need to make sure the data you want to render in template is available before you actually render the template on page. This is what I use for rendering template on page:
UI.DomRange.insert(UI.render(Template.template_name).dom, document.body);
Although my use case for rendering templates client side is somewhat different (my task was to live update the changed template overriding meteor's hot code push), but this worked best among different methods of rendering the template.
You can check my very early stage package which does this here: https://github.com/channikhabra/meteor-live-update/blob/master/js/live-update.js
I am fairly new to real-world programming so my code might be ugly, but may be it'll give you some pointers to solve your problem. (If you find me doing something stupid in there, or see something which is better done some other way, please feel free to drop a comment. That's the only way I get feedback for improvement as I am new and essentially code alone sitting in my dark corner).
I have a custom template file I'm using for a page.
Say the page is www.mydomain.com/hello-world
The content of this page is taken from a template file called hello-world.tpl.php
Now I need to have a variable prepared in advance for that page, so I took a look at how core modules achieve this and tried to implement in the same way, only the variables are always null..
for hello-world.tpl.php I created in my module file a function called:
function template_preprocess_hello_world(&$variables) {
$variables['test'] = "test";
}
As I said $test doesn't get any value on www.mydomain.com/hello-world (I receive NULL when var dumping it)
I spent an hour or so double checking that I don't have any typos or anything like that.
Is what I'm doing worng??
Try renaming the function to mymodulename_preprocess_hello_world(&$variables). Don't forget to clear the cache as well.
In View,
#{
Layout = "~/Views/Shared/site.cshtml";
ViewBag.Title = "Organizations";
var organizations = "";
foreach (var org in Model)
{
organizations += "'" + org.Name + "':'" + org.Id + "',";
}
organizations = organizations.Substring(0, organizations.Length - 1);
}
Result operation: organizations = "'Passport':'14f0eac0-43eb-4c5f-b9fe-a09d2848db80','Bank':'ad1d77d8-7eb1-4a4c-9173-b0f2f7269644'";
Output the data in section JS code.
But when viewing the source code of the page in the browser, not getting what wanted.
What's the problem? How to make a normal quotes?
JS: "data": "#organizations"
Result in view webpage returned "data": "'Passport':'14f0eac0-43eb-4c5f-b9fe-a09d2848db80','Bank':'ad1d77d8-7eb1-4a4c-9173-b0f2f7269644'"
OK cool Q,try this source:
#{
var model = Model.ToArray().Select(org => string.Format("'{0}':'{1}'", org.Name, org.Id));
var data = string.Join(",", model);
}
#Html.Raw(data)
What if you change
"data": "#organizations"
to
"data": "#Html.Raw(organizations)"
#Html.Raw(content)
And check this one out: http://jeffreypalermo.com/blog/what-is-the-difference-in-lt-variable-gt-and-lt-variable-gt-in-asp-net-mvc/
In your code example here, the culprit is the
#organizations
that generates the quotes. You could instead use:
#Html.Raw(organizations)
Okay, that's great, but by creating JSON, you are doing work the framework could be doing for you. You probably want a model that the framework can serialize for you. This way you don't even need any code in your view header at all.
#Html.Raw(JsonConvert.SerializeObject(Model.ToDictionary(m => m.Name, m => m.Id))))
Above, note that I'm using Json.NET, which you probably want to NuGET into your project because Microsoft is moving to it. No point in figuring out how to use the old JSON serializer to do this. Also note that unless you are using the model for other purposes, you might choose to do the dictionary conversion outside the view, reducing the code-work in the view.
Next, if you are embedding JSON in the view, you might want to consider one of two other options. If the amount of data will be small, consider using the join method proposed by eli (here), but instead encoding it in HTML 5 "data-" elements and loading it using JavaScript. That way you keep javascript out of your view. It's just one more step of confusing when debugging javascript, looking for variables that are initialized by dynamically-generated HTML.
Better yet, create a reusable HTML helper method to transform your model into data attributes: How to use dashes in HTML-5 data-* attributes in ASP.NET MVC
Finally, if there are MANY JSON elements, consider sending the data separately. Render it with a simple Json() method in your controller, and get it with a simple jQuery $.json() in your client-side code. See here for an example
Good luck!
How can I build a block in Drupal which is able to show the node ID of the view page the block is currently sitting on?
I'm using views to build a large chunk of my site, but I need to be able to make "intelligent" blocks in PHP mode which will have dynamic content depending on what the view is displaying.
How can I find the $nid which a view is currently displaying?
Here is a more-robust way of getting the node ID:
<?php
// Check that the current URL is for a specific node:
if(arg(0) == 'node' && is_numeric(arg(1))) {
return arg(1); // Return the NID
}
else { // Whatever it is we're looking at, it's not a node
return NULL; // Return an invalid NID
}
?>
This method works even if you have a custom path for your node with the path and/or pathauto modules.
Just for reference, if you don't turn on the path module, the default URLs that Drupal generates are called "system paths" in the documentation. If you do turn on the path module, you are able to set custom paths which are called "aliases" in the documentation.
Since I always have the path module turned on, one thing that confused me at first was whether it was ever possible for the arg function to return part of an alias rather than part of system path.
As it turns out, the arg function will always return a system path because the arg function is based on $_GET['q']... After a bit of research it seems that $_GET['q'] will always return a system path.
If you want to get the path from the actual page request, you need to use $_REQUEST['q']. If the path module is enabled, $_REQUEST['q'] may return either an alias or a system path.
For a solution, especially one that involves a view argument in the midst of a path like department/%/list, see the blog post Node ID as View Argument from SEO-friendly URL Path.
In the end this snippet did the job - it just stripped the clean URL and reported back the very last argument.
<?php
$refer= $_SERVER ['REQUEST_URI'];
$nid = explode("/", $refer);
$nid = $nid[3];
?>
Given the comment reply, the above was probably reduced to this, using the Drupal arg() function to get a part of the request path:
<?php
$nid = arg(3);
?>
You should considder the panels module. It is a very big module and requires some work before you really can tap into it's potential. So take that into considderation.
You can use it to setup a page containing several views/blocks that can be placed in different regions. It uses a concept called context which can be anything related to what you are viewing. You can use that context to determine which node is being viewed and not only change blocks but also layout. It is also a bit more clean since you can move the PHP code away from admin interface.
On a side note, it's also written by the views author.
There are a couple of ways to go about this:
You can make your blocks with Views and pass the nid in through an argument.
You can manually pass in the nid by accessing the $view object using the code below. It's an array at $view->result. Each row in the view is an object in that array, and the nid is in that object for each one. So you could run a foreach on that and get all of the nid of all rows in the view pretty easily.
The first option is a lot easier, so if that suits your needs I would go with that.
New about Drupal 7: The correct way to get the node id is using the function menu_get_object();
Example:
$node = menu_get_object();
$contentType = node_type_get_name($node);
Drupal 8 has another method. Check this out:
arg() is deprecated