I'm trying to load in partials from a separate file while using mustache.js but it's proven difficult. The PHP implementation makes this very easy, but not so much in the JS side.
I've gone through the docs and can't find anything related to this, only using an object as a partial instead of a file.
Here's some sort of psuedocode to explain what I'm trying to do.
$.Mustache.load('/mustaches.php', function () {
var item = { thing: 'one' };
var partial = 'partials/actions.mustache';
$('.container').mustache(
'main_mustache',
{item: item},
partial
);
});
So, I'd like to be able to load a secondary file as a partial an include it with the template to be used so I don't have to duplicate code across all the different templates I use.
With something like Blaze I can import a template with {{> templateName}} but it doesn't seem to be quite so easy with Mustache.js.
If this isn't possible with Mustache, what other libraries would you recommend?
You could load both templates with mustache, and then pass one of them (the partial) to the one that should render the partial. Be aware that in order to make it work, in the mustache where you want to render the partial, the variable name should be enclosed in triple curly bracers in order to tell mustache that it should be html:
<div>
<h1>This is my title</h1>
{{{partial}}}
</div>
and then:
$('.container').mustache(
'main_mustache',
{item: item, partial: partial},
);
Related
I just started using Sapper (https://sapper.svelte.technology) for the first time. I really like it so far. One of the things I need it to do is show a list of the components available in my application and show information about them. Ideally have a way to change the way the component looks based on dynamic bindings on the page.
I have a few questions about using the framework.
First, I'll provide a snippet of my code, and then a screenshot:
[slug].html
-----------
<:Head>
<title>{{info.title}}</title>
</:Head>
<Layout page="{{slug}}">
<h1>{{info.title}}</h1>
<div class="content">
<TopBar :organization_name />
<br>
<h3>Attributes</h3>
{{#each Object.keys(info.attributes) as attribute}}
<p>{{info.attributes[attribute].description}} <input type="text" on:keyup="updateComponent(this.value)" value="Org Name" /></p>
{{/each}}
</div>
</Layout>
<script>
import Layout from '../_components/components/Layout.html';
import TopBar from '../../_components/header/TopBar.html';
let COMPONENTS = require('../_config/components.json');
export default {
components: {
Layout, TopBar
},
methods: {
updateComponent(value) {
this.set({organization_name: value});
}
},
data() {
return {
organization_name: 'Org Name'
}
},
preload({ params, query }) {
params['info'] = COMPONENTS.components[params.slug];
return params;
}
};
</script>
Now my questions:
I notice I can't #each through my object. I have to loop through its keys. Would be nice if I could do something like this:
{{#each info.attributes as attribute }}
{{attribute.description}}
{{/each}}
Before Sapper, I would use Angular-translate module that could do translations on strings based on a given JSON file. Does anyone know if a Sapper/Svelte equivalent exists, or is that something I might need to come up with on my own?
I'm not used to doing imports. I'm more use to dependency injection in Angular which looks a bit cleaner (no paths). Is there some way I can create a COMPONENTS constant that could be used throughout my files, or will I need to import a JSON file in every occurence that I need access to its data?
As a follow-up to #3, I wonder if there is a way to better include files instead of having to rely on using ../.. to navigate through my folder structure? If I were to change the path of one of my files, my Terminal will complain and give errors which is nice, but still, I wonder if there is a better way to import my files.
I know there has got to be a better way to implement what I implemented in my example. Basically, you see an input box beside an attribute, and if I make changes there, I am calling an updateComponent function which then does a this.set() in the current scope to override the binding. This works, but I was wondering if there was some way to avoid the function. I figured it's possible that you can bind the value of the input and have it automatically update my <TopBar> component binding... maybe?
The preload method gives me access to params. What I want to know if there is some way for me to get access to params.slug without the preload function.
What would be really cool is to have some expert rewrite what I've done in the best possible way, possibly addressing some of my questions.
Svelte will only iterate over array-like objects, because it's not possible to guarantee consistent behaviour with objects — it throws up various edge cases that are best solved at an app level. You can do this sort of thing, just using standard JavaScript idioms:
{{#each Object.values(info.attributes) as attr}}
<p>{{attr.description}} ...</p>
{{/each}}
<!-- or, if you need the key as well -->
{{#each Object.entries(info.attributes) as [key, value]}}
<p>{{attr.description}} ...</p>
{{/each}}
Not aware of a direct angular-translate equivalent, but a straightforward i18n solution is to fetch some JSON in preload:
preload({ params, query }) {
return fetch(`/i18n/${locale}.json`)
.then(r => r.json())
.then(dict => {
return { dict };
});
}
Then, you can reference things like {{dict["hello"]}} in your template. A more sophisticated solution would only load the strings necessary for the current page, and would cache everything etc, but the basic idea is the same.
I guess you could do this:
// app/client.js (assuming Sapper >= 0.7)
import COMPONENTS from './config/components.json';
window.COMPONENTS = COMPONENTS;
// app/server.js
import COMPONENTS from './config/components.json';
global.COMPONENTS = COMPONENTS;
Importing isn't that bad though! It's good for a module's dependencies to be explicit.
You can use the resolve.modules field in your webpack configs: https://webpack.js.org/configuration/resolve/#resolve-modules
This would be a good place to use two-way binding:
{{#each Object.values(info.attributes) as attr}}
<p>{{attr.description}} <input bind:value=organization_name /></p>
{{/each}}
Yep, the params object is always available in your pages (not nested components, unless you pass the prop down, but all your top-level components like routes/whatever/[slug].html) — so you can reference it in templates as {{params.slug}}, or inside lifecycle hooks and methods as this.get('params').slug, whether or not a given component uses preload.
I have a route for different pages of store profiles in my Node app. Been googling, and I know I can edit the parameters, but I have absolutely no idea how to change the content (loading with React) based on name. I'm just using res.render() to render the specific page.
For example, https://www.instagram.com/adidas shows different content than https://www.instagram.com/nike however, they have the same HTML structure and base profile HTML. It's just the content that is different!
Right now, I just have an store.ejs that is the html structure of each profile.
What's an example for how to change and load content based on the name/id?
Route parameters is probably what you're looking for.
app.get('/:name', (request, response) => {
let locals = {
name: request.params.name,
foo: 'bar'
};
res.render('store.ejs', locals);
});
The local variables can be referenced within your template file.
<h1>Hello <%= name %></h1>
<button><%= foo %></button>
Then navigating to /rohit is going to render a page that contains the following markup.
<h1>Hello rohit</h1>
<button>bar</button>
That said, there are many other ways to build application routes, so it's definitely worth reading the routing docs.
I'm trying to utilize two 3rd party widgets on a website however cannot quite figure out how to get Ember.js to cooperate. I found lots on Views and have found that they're deprecated now and Components seem the way to go however I'm not sure how to make this work...
I have various city-based templates that require:
<script type="text/javascript" src="http://www.topix.net/iframe/city/atco-nj?js=1"></script>
and one other that looks like this:
<script>document.write('<script src="... + Math.random() + ..."></script>');</script>
How would I do this with Components or a better alternative!?
For this you don't really need a component, you could just create a template and inject it wherever you need it. However I'm not 100% what are city based templates but just to output html you can just use a template template / helper:
using a template (known as partial):
run (if using ember cli , if not just create the template file somewhere, again assuming you have some way you're compiling templates on the server)..
ember g partial inject_city
then:
//inject_city.hbs
<script type="text/javascript" src="http://www.topix.net/iframe/city/atco-nj?js=1"></script>
then in your main template:
{{partial 'inject_city'}}
Further reading: http://guides.emberjs.com/v1.10.0/templates/writing-helpers/
using a helper (notice to return html you must use the safestring)
Ember.Handlebars.helper('injectScript', function(value, options) {
return new Ember.Handlebars.SafeString("<script>document.write('<script src="... + Math.random() + ..."></script>');</script> );
});
In version 1.13.0 and above the syntax is different:
import Ember from "ember";
export default Ember.Helper.helper(function(params) {
return Ember.String.htmlSafe(`<b>${params[0]}</b>`);
});
(Notice you should generate a helper, wrap it with Helper.helper and return Ember.String.htmlSafe).
further reading: http://guides.emberjs.com/v1.10.0/templates/writing-helpers/
However the best way is to include libraries in your ember build / build your own component from by using the building blocks, and not just include a whole script..The ember documentation explains about components pretty well and ember-cli docs explain how to include third party libs..
Best of luck!
I got this to work by making a component. I had the same sort of problem, I wanted to draw some pie charts at load time of the page using charts.js
SO i defined the charts and ran the js to create them in a component.
heres the component 'js-charts':
export default Ember.Component.extend({
didInsertElement: function() { insert script and or methods to run }
});
This will always trigger because of the didInsertElement.
and in the template of the page your rendering just add {{js-charts}} component
I'm trying to build a basic web application with Backbone.JS and already encounter understanding issues in the very beginning.
I was thinking about the following HTML structure:
<script type="text/template" class="t_show">FOO</script>
static foobar
<script type="text/template" class="t_show">BAR</script>
where static foobar always gets rendered - .t_show however only, when the router matches #show.
That's my current backbone code:
var v_show = Backbone.View.extend({
el: $(".client"),
template: _.template( $( '.t_show' ).html() ),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
},
that kind of already works, however only renders the very first template-partial (FOO) and the static code (static code), but no (BAR).
Ling story short: How to realise template snippets belonging to the same view in Backbone?
jquery's .html() function will only return the html of the first matched element, so calling _.template($('.t_show').html()) will only pass FOO to the template function.
There's a couple ways you could resolve this:
If you want FOO and BAR to render right next to each other (styling aside), you can combine them into a single template. I'm guessing this doesn't work for your use case or you wouldn't have asked about supporting multiple templates, but included it for completeness.
Iterate through each .t_show and add the html() bits together, and pass the result to _.template(). This also will show FOO and BAR next to each other.
Assign each template to its own variable and then execute and render the templates separately.
That last option has the most flexibility as you can place the resulting html in different parts of your view if you wish, or you could re-render them individually which is handy if they're fairly isolated or either is kind of heavy to render. That might look something like this:
fooTemplate: _.template($('.foo.t_show').html()),
barTemplate: _.template($('.bar.t_show').html()),
render: function() {
this.$el.html(this.fooTemplate(this.model.attributes));
this.$el.append(this.barTemplate(this.model.attributes));
return this;
},
...
I'm currently reusing a template to populate a list using the code below:
<li>
{% include "ding/search_result.html" with title=field.title url=field.url description=field.description %}
</li>
When new data comes in, I want to be able to add new elements to my list dynamically from javascript. I can use the code below to add new list items:
$("ul.search-results-list").append('<li>New List Item</li>')
Is there a way for me to append the reusable template code I'm using, and pass in the appropriate parameters?
Yes there is! AND you get to refactor your APIs as well.
Imagine that you have an API that returns this json blob for every new list item.
{
name: "limelights"
}
And let's just use jQuery for this (even though I kinda don't want to.)
So you query the API like this
$.getJSON('api/v1/getName.json', {'someParameter', 123}, function() {
//this is where you would do your rendering then.
});
So how to do the rendering? Well, I'm a huge fan of underscore.js and it's rendering of templates, so I'm gonna go ahead and use that (but you can exchange it for Mustasche, Handlebars, Hogan or whatever you fancy).
First, we'll define a script template like this: (We're using underscore.js own ERB style template language).
<script type="text/template" id="my_fancy_list">
<li><%= name %></li>
</script>
Now this can live pretty much anywhere, either in your template or you can require it in if you're using Require.JS but we're gonna assume that it lives in your template (Hint: it could be rendered by some Django template tag)
Anyhoo,
Fill this template with data now:
var template = _.template($('script#my_fancy_list').html());
//this will give you the template as a javascript function.
//Query the API
$.getJSON('api/v1/getName.json', {'startsWith': 'l'}, function(data) {
$('ul.search-results-list').append(template(data));
});
And presto, you now have an JavaScript driven application that renders new data that comes from the server without fetching the entire template and render it all again.