assemble.io partial pass data to nested partials - json

I am using assemble.io and I would want to modularize everyhing using the "atomic design" principles.
Let's say that I start with a couple of single atoms
atomic partial "title" (a-h2-title.html)
<h2 class="{{additionalclasses}}">{{title}}</h2>
atomic partial "info text" (a-info-text.html)
<div class="info {{additionalclasses}}">
{{{text}}}
</div>
As far as I have understood, if I want to use "instances" of these generic components with some data I can define them in a json file like in this example:
info-text-example1.html
{{>a-info-text info-text-example1}}
info-text-example1.json
{
"text":"<p>some text</p>",
"additionalclasses"="info--modified"
}
Ok, now my problem is when I want to define for example a molecule:
m-text-and-title.html
<div class="box {{additionalclasses}}">
{{>a-h2-title}}
{{>a-info-text}}
</div>
Now, if I want an "instance" for this element
text-and-title-example1.html
{{>m-text-and-title ???}}
How can I define all the data for the object itself (additionalclasses) and for the child objects?
I hope I have made myself clear
I've already seen this article here but I am not able to adapt it to my case
Thank you for your answer

You will still have to create the data structure in a way that you need it, then in the pages or partials pass the values to the sub-partials. So in this case, I think you can use the following pattern:
text-and-title-example1.html
{{>m-text-and-title text-and-title-example1}}
text-and-title-example1.json
{
"additionalclasses": "text-and-title--modified",
"title-example": {
"title": "some title",
"additionalclasses": "title-modified"
},
"text-example": {
"text": "<p>some text</p>",
"additionalclasses": "info--modified"
}
}
Then update the molecule to be this:
<div class="box {{additionalclasses}}">
{{>a-h2-title title-example}}
{{>a-info-text text-example}}
</div>
Now this works the same way as your initial example. You have a data object with properties that you've specified, then you pass those properties into the partials that will use them. The "atoms" have generic, reusable properties already and you can change your "molecule" to do the same... like change title-example to title and text-example to text, but keep them as objects that are passed down to the "atoms".

Related

In an Angular page containing custom components, how should I make sure all IDs are unique to get rid of the warnings?

I have a custom component for text input and each of them has an internal field ID'ed as data. It causes the warning below to appear.
[DOM] Found 13 elements with non-unique id #data
I'm clear on why it happens and I understand that's a warning not an actual error. I also recognize the appropriateness of an ID being unique (in its scope).
I'm not entirely sure regarding the implications in my particular case. In my opinion, warnings are tolerable but not acceptable.
Is there a best-practice approach to get rid of the error? By the very concept of a GP component, some parts will be alike in each instance. Or is there a trick to unique'fy the IDs? Or perhaps a directive or such to let Angular know we're cool with the state as is?
The component uses #ViewChild("data") to refer the input control in the template below.
<div id="outer">
...
<label for="data">{{label}}</label>
<input #data id="data" ... >
<div *ngFor="let error of errors" class="row"> ... </div>
</div>
As far as I understand the purpose of using ids is querying it inside of Angular. You could use a directive or another attribute to query without any warnings. Also you could make a kind of wrapper which would apply common ID to input and its label and just concat UUID and ID you want to use. But if it's only about querying just choose another attribute. For example data-id or data-qa whatever gives you an ability to query and have no errors at the same time. Just in case #ViewChild("data") refers to #data and not id="data" whilst you may wrap input with label tag.

How would you embed atomic partials into a template data object

I'm using handlebars and assemble with yeoman and gulp.
I want to have some globalized partials that are able to be nested or injected into another partial by calling it within the context of a data object.
A simple example of that would be having a list of links that I could reference inside content throughout the site. The reason behind this, is the need for consistency. If for example, if I have a link within text on a page that I reference a 15 times throughout an entire website, but then realize I need to add a trade mark or modify the text, I want to update it once, not 15 times.
This is an example of what I want to do. Define global data inside a json file:
links.json
{
"apple": {
"linktext": "apple",
"target": "_blank",
"href": "http://www.apple.com"
},
"blog-article-foo-bar": {
"linktext": "foo bar",
"href": "http://www.foobar.com"
},
"dell": {
"linktext": "dell",
"target": "_parent",
"href": "http://www.dell.com"
}
}
Generate a partial from that content using a simple or complex template:
links.hbs
<a href="{{href}}" {{#if target}}target="{{target}}"{{/target}}>{{linktext}}</a>
And be able to embed that partial into another one by referencing it some how. This didn't work, but I've been reading about custom helpers, but can't figure out how I would intercept the partial and bind it into the other partial.
text.json
{
"text": "If you need a computer, go to {{> link link.apple}}."
}
text.hbs
<p>
{{text}}
</p>
compiled.html
<p>
If you need a computer, go to apple.
</p>
If you have suggestions or examples that might help me understand how to achieve this, I'd really appreciate the support. Thanks in advance.
There is some information about Handlebars helpers in their docs but not that much.
Since you're trying to use handlebars syntax in the value of a property on the context (e.g. text), handlebars won't render the value since it's already rendering the template. You can create your own helper that can render the value like this:
Handlebars.registerHelper('render', function(template, options) {
// first compile the template
const fn = Handlebars.compile(template);
// render the compiled template passing the current context (this) to
// ensure the same context is use
const str = fn(this);
// SafeString is used to allow HTML to be returned without escaping it
return new Handlebars.SafeString(str);
});
Then you would use the helper in your templates like this:
{{render text}}
Thanks for the example #doowb, your code did work but not for what I was trying to do. I really wanted something more complicated but I simplified my question not knowing it would be an issue. The code you provided worked (I think after a slight tweak) for a simple render of a template, but my templates use helpers such as #each and #if which caused the issue. Where the helpers were in my template, I ended up getting async placeholders. For example: <a $ASYNC$1$3...> I later learned this has to do with how partials are rendered. Understanding that lead me to subexpressions and the below solution.
Keeping my example above with some modifications, this is how I was able to merge partials.
First, I simplified the placeholder in text.json to basically a unique ID, instead of trying to render the partial there.
On the hbs template that I'm rendering to, such as a page or whatever, I included the insert helper with 3 arguments. The first two are subexpressions, each return a flattened partials as strings. The key here is that subexpressions process and return a result before finishing the current process with the helper. So two flattened templates are then sent to the helper along with the placeholder to search for.
The helper uses the third argument in a regex pattern. It searches the second argument (flattened parent template) for this pattern. When found, it replaces each instance of the pattern with the first argument (yes its a global fine replace).
So, the flattened child string gets inserted into parent each time placeholder is found.
First argument
(partial "link" link.apple)
Returns
'apple'
Second argument
(partial "text" text.text-example)
Returns
'<p class="text font--variant">If you need a computer, go to {{linkToApple}}.</p>'
Third argument
'linkToApple'
text.json
{
"text-example": {
"elm": "quote",
"classes": [
"text",
"font--variant"
],
"text": "If you need a computer, go to {{linkToApple}}."
}
}
text.hbs
<{{elm}} class="{{#eachIndex classes}}{{#isnt index 0}} {{/isnt}}{{item}}{{/eachIndex}}">{{text}}</{{elm}}>
compile.hbs
{{insert (partial "link" link.apple) (partial "text" text) 'linkToApple' }}
compile.html
<p class="text font--variant">If you need a computer, go to apple.</p>
gulpfile.js
app.helper('insert', function(child, parent, name) {
const merged = parent.replace(new RegExp('\{\{(?:\\s+)?(' + name + ')(?:\\s+)?\}\}', 'g'), child);
const html = new handlebars.SafeString(merged);
return html;
});
Hope this helps someone else. I know this can use improvements, I'll try to update it when I get back to cleaning up my gulp file.

Space Between Text In Same JSON String

I am volunteering to write a quick AngularJS App for a non-profit. I have set up Angular successfully but the one problem I am coming across stems from the JSON.
I have a JSON object that contains multiple paragraphs. Therefore I need to separate the paragraphs onto two lines. I did some research and I found some answers to similar questions but because they were not put in context I did not understand them. I tried looking to see if JSON had something built in that forced a line break, because that would do, but I did not find that.
Help is greatly appreciated!
HTML w/ Angular JS
<div class="bio">
{{exhibits[whichItem].bio}}
</div>
JSON
[
{
"name":"Name goes here",
"bio":"First long block of text goes here then it needs a break <br /> and the second long block of text is here."
}
]
#user5854648 Your back-end sending the JSON response in this format .If you are using angular version greater than 1.2 to display the text content with html tags(People's calling this as unsafe html ) use angularjs inbuilt service called $sce .To make it as a reusable component created a custom filter.
var demoApp = angular.module('demoApp',[]);
demoApp.filter('trustAsHtml', [
'$sce',
function($sce) {
return function(value) {
return $sce.trustAsHtml('html', value);
}
}
]);
then make changes in html like
<div class="bio">
{{exhibits[whichItem].bio | trustAsHtml}}
</div>
or
<div class="bio">
<p ng-bind='exhibits[whichItem].bio | trustAsHtml'></p>
</div>

Creating templates dynamically from JSON in AngularJS

I am parsing or reading a JSON file in my AngularApp. I want to create one template for each object inside the JSON file, and then load it with "previous" and "next" in my app.
So i have a JSON file, for example:
{
"name": "test",
"objects":[
{"one": "text here", "id" : "1" },
{"two": "and text there", "id" : "2" }
]
}
So i want to create a template called "template1" and "template2".
I am starting with Angular, so i don't need a whole workaround, just where do i have to dig deeper?
I created a controller for my app
I've then created a jsonService which injectes the controller
Now i have the JSON data
But what then? Do i have to create Directives? And how to load them into my main-page? With data-ng-view?
See this example which will give you an example of how you can iterate over json and render to html:
https://github.com/eu81273/angular.treeview/blob/master/angular.treeview.js
Thanks #Nikos for this possibility. I found a much simpler soultion:
I hard coded a ng-switch on="option" and then a ng-switch-when="optionN" in each div, so i can dynamically adjust one template to fit all options.

Razor: Retrieving variable from component template on page template

Hi all,
I've been working on a set of Razor templates that is either Site Editable with the Experience Manager and at the same time is fully responsive for several screenwidths with the Twitter bootstrap. As a result, I need to dynamically manipulate the DOM output based on what the Experience Manager editor adds or deletes but still maintain the responsive design. Part of this construction is adhering to the rules the twitter bootstrap dictates.
The twitter bootstrap allows for excellent responsive design by introducing dynamically calculated div widths using classes. A <div class="span12> uses the entire width of the wrapper, for example. A "span6" effectively uses half, with a certain margin calculated as well to allow for another div with "span6". However, this only works if the preceding class is called <div class="row-fluid">,and as long as the span<numbers> actually add up to exactly 12. The problem arises when I need to close the <div class="row-fluid"> when this number is actually reached.
To clarify: it has to output like this
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span4">..code</div>
<div class="span2">..code</div>
</div>
The <div class="span[#]"> are rendered with a component template, in order to allow for multiple components within the <div class="row-fluid>, which the Page Template renders.
However, from a component template level I cannot seem to retrieve the actual amount of components of this template actually exist on the Page itself. I calculate the width of the component used based on a schema option of the component itself. I use the following Component Template code to render it correctly:
#{
var spanClass = String.Empty;
if (Fields.HasField("component_width") && Fields.component_width != null) {
if (Fields.component_width.ToLower() == "full") {
spanClass = "span12";
} else if (Fields.component_width.ToLower() == "half") {
spanClass = "span6";
} else if (Fields.component_width == "40%") {
spanClass = "span5";
} else if (Fields.component_width == "35%") {
spanClass = "span4";
} else if (Fields.component_width == "25%") {
spanClass = "span3";
}
}
}
<div class="#spanClass">...code
To get to my question: I need to be able to close the <row-fluid> div if the number 12 has been reached. So if one component with the options 'Full' (width) is selected, the following output code needs to appear:
<div class="row-fluid">
<div class="span12">..code</div>
</div>
If there are two components on the page with the option "half" are selected, it must allow
<div class="row-fluid">
<div class="span6">..code</div>
<div class="span6">..code</div>
</div>
mind the closing div on the end. Is there some way I can reach the variable i created on the Component Template var spanClass = String.Empty; from Page Template? Something like:
#foreach (var cp in GetComponentPresentationsByTemplate("XM_Generic Content")) {
#if (cp.Component.spanClass == "span6") {
<div class="row-fluid">
#cp.RenderComponentPresentation()
#if (cp.Index == 1) {
</div>
}
}
}
I'm still getting to know Razor templates, the practicalities of Responsive design and ofcourse StackOverflow. Chances are that I completely missed something, made dumb errors in my code of just asked a silly question. By all means, let me know.
The package is not shared between template runtimes, so this behavior is normal (not being able to see variables set in one template from a different instance).
There are ways around this, but you should consider that perhaps there is a good reason why Tridion chose to isolate the template execution.
See here for one of the ways to go around this.
Standard techniques using the ContextVariables dictionary don't allow you to set something in the CT and access it from the PT. Effectively, each time a Component is rendered, the render context gets a fresh copy of the variables from the page render context. Writing back to them, therefore isn't effective. There is a technique that gets round this, which is described in detail on tridion-practice. As already noted, resorting to these kinds of techniques shouldn't be your first option, but sometimes you need to.
Currently, its seems, the user is defining the width position in the component field. I think, its quite typical, but if you create 5 Component Template which will call a same Razor TBB, and also define, a parameter schema on component Template where can set the width of component then afterwards you can easily call these different CTs in the page template.