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
Related
So, I'm trying to setup Aurelia in my Angular 1 web application so I can slowly upgrade. I need to do that since the application is too big and migrating everything at once would be impossible.
So, in my Aurelia folder I created a component folder with two components (aurelia-component.js and another-component.js with their views aurelia-component.html and another-component.html), I won't put the javascript as they are just two classes with one property, the html for both is the same, the only thing that changes is the text property value so I can differentiate them:
<template>
<div>${text}</div>
</template>
My entry point main.js looks like this:
export function configure(aurelia) {
aurelia.use
.basicConfiguration()
.developmentLogging()
.globalResources('components/aurelia-component')
.globalResources('components/another-component');
//window.aurelia = aurelia;
aurelia.start()
.then(a => {
window.aurelia = a;
});
}
As you can see, this puts Aurelia in the window object so I can access it from my Angular app, I'll improve this later.
In my angular app I have this directive:
'use strict';
function AureliaContainer() {
function Link($scope, element, attrs) {
window.aurelia.enhance(element[0]);
}
//
return {
restrict: 'A',
link: Link
};
}
module.exports = AureliaContainer;
I set this up in my app root with:
app.directive('aureliaContainer', require('./directives/aurelia.container'));
And in my Angular View I have these divs with my directive that calls the enhance function from Aurelia:
<div aurelia-container>
<aurelia-component></aurelia-component>
</div>
<div aurelia-container>
<another-component></another-component>
</div>
The reason I have two aurelia-container in the html is that I know I'll have to have more than one when I'm migrating the application.
And this works fine, both components load normally in the screen.
The problem is when I try to call another component from within one of those components.
What I did was, I created a new component called test-component.js with its view test-component.html. The html for this is just:
<template>
<h1>Header</h1>
</template>
And then, from the aurelia-component.html I called it using:
<template>
<require from="./test-component"></require>
<div>${text}</div>
<test-component></test-component>
</template>
Now, when I load the page, the test-component actually loads but the <div>${text}</div part of aurelia-component doesn't and I get this error in the console:
Uncaught (in promise) TypeError: Cannot read property 'behaviorInstructions' of undefined
I really don't understand why this error is happening, I should be able to load a custom element from within another one normally, shouldn't I. Or is there a limitation when you use enhance?
I also tried to use setRoot in both divs with no success, just one of them is loaded.
Maybe there's a better approach for this?
Again, I can't migrate my entire application at once, it's just no feasible.
Thanks in advance for the help.
First off, I know nothing about progressive enhancement in Aurelia. And cannot comment about its suitability for your scenario.
But I am wondering if maybe you missed some Au dependencies (like binding or templating?)
http://aurelia.io/hub.html#/doc/article/aurelia/framework/latest/app-configuration-and-startup/8
aurelia.use
.defaultBindingLanguage()
.defaultResources()
.developmentLogging()
.globalResources('resources/my-component');
That might explain why it fails when you want it to render a template?
I've started work on an e-learning delivery platform and we've chosen Angularjs (1.2.29 because we still have users on IE8). Our team is all relatively new to Angular and we're not sure what is best practise to deliver the system to brief.
The aim is to have a very component-based structure, where designers can simply edit a json file, adding named components as they require them. Behind the scenes, each component should have its own html template, js functionality file and css.
We have a working system which so far includes 'paragraph' and 'image' components. The next step was to add a 'popup' component that has some interactive functionality.
The problem I can already see forming is that we're adding the component functionality into the 'pageController' in our app.js file, which I suspect is a very bad idea, not least because if we keep adding each component's functionality there, the file will become huge and unwieldy. Here's the pageController in app.js, so far:
app.controller('pageCtrl', ['$scope', '$routeParams', '$http', 'content', function($scope, $routeParams, $http, content) {
$http.get('json/page' + $routeParams.pageId + '.json')
.success(function(data) {
$scope.page = data;
});
$scope.getStyle = function(singleCase, device) {
if (singleCase == undefined)
return '';
return assignBootstrap(singleCase, device);
}
// function for new, interactive 'popup' component
$scope.showPopup = function (showOnClick) {
// presentation logic located here. This is a bad idea, right?
if ($('#'+showOnClick).hasClass('overlay')) {
$('#page_container').append($('#'+showOnClick));
}
$( '#' + $( '#' + showOnClick ).attr('data-replaces') ).remove();
$('.popup').addClass("hidden");
$('#'+showOnClick).removeClass("hidden");
}
$scope.pageId = $routeParams.pageId;
}]);
I have read and watched a lot of tutorials, and pages on the Angular site, but comprehending how to get the specific requirements of our project working with Angular is proving difficult.
This page...
https://code.angularjs.org/1.2.29/docs/guide/controller
...tells me that DOM manipulation code should be encapsulated in directives (either custom or built in, I assume).
Given that we want to end up with small .js files associated with each required component, should we instead refactor the design to use custom element (restrict: "E") directives to encapsulate the functionality?
The information I've encountered is so concept-based and abstract, it is difficult to know how the concepts should be best applied to a working project.
Is it a good use of 'element restricted' directives (effectively custom html tags) to encapsulate our individual components' code? I can imagine ending up with a list of custom html tags that define the components we need. Is that even what element directives are for?
Thanks.
The answer to your question is yes, that's the purpose of directives: inject in your HTML some reusable components in an intelligent way.
Think if you ever need to bind a variable to your "components": you'll be able to do it easily and with no pain at all, by using directives/components.
This way of using your views goes against the angular way of things:
$scope.showPopup = function (showOnClick) {
// presentation logic located here. This is a bad idea, right?
if ($('#'+showOnClick).hasClass('overlay')) {
$('#page_container').append($('#'+showOnClick));
}
$( '#' + $( '#' + showOnClick ).attr('data-replaces') ).remove();
$('.popup').addClass("hidden");
$('#'+showOnClick).removeClass("hidden");
}
because you'll end up replicate this code all over your controllers.
.
Alternatively, if you don't need any form of logic inside your "containers", you could use ng-include with templates to inject html in your pages, like this:
<div ng-include"myContainer.html"></div>
and somewhere in your html pages, include a script
<script type="text/ng-template" id="myContainer.html">
<!-- content -->
</script>
I'm pretty lost after trying numerous different things. I am building an Ember site and inside of one of my Handlebars templates, I want to display a link only if a condition is true. Here is my template.
<script type="text/x-handlebars" data-template-name="project">
<div class="project-container">
{{is_external model.url model.title}}
</div>
</script>
Now, my registerHelper in my js file:
Handlebars.registerHelper('is_external', function(url, title, options) {
if (url.indexOf("codepen") < 0) {
return "<p class='view-external-link'>"+
"<a href='{{url}}'' aria-label='View {{title}}'' target='_blank'>Visit Site</a>"+
"</p>";
}
});
The error I keep receiving however, is:
Uncaught TypeError: Cannot read property 'isHelperFactory' of undefined coming from my ember.js file.
Ideally, I would prefer to just return true or false from the helper to keep the Html out of my helper function but first I just need some help getting it working.
I am including ember, ember_compiler, and handlebars on my page as well.
My understanding of Ember is that since even 1.x, Ember included its own instance of Handlebars, so your external instance might be interfering.
The Ember v2.2.0 documentation on templates says to use Ember.Helper.helper, as does v1.13.0. Maybe give that a try and see if it helps.
What is the version of your Ember?
When i generate helper Ember uses syntax like this
import Ember from "ember";
// http://emberjs.com/deprecations/v1.x/#toc_ember-select
export function checkEquality([leftSide, rightSide]) {
return leftSide === rightSide;
}
export default Ember.Helper.helper(checkEquality);
In the template
{{is-equal item.selection selection}}
And if you want to use html within helper
you need to return
yourHtml.htmlSafe();
I'm trying to display a string, pulled from my model, that contains ember custom components. They don't seem to get compiled though -- see (1) and (2) in the output. If I replace the custom components with standard html elements and use the {{{-}}} syntax for binding, things look right (see (3) and (4) in the output), but this is not sufficient for the application I have in mind, though. How can I get ember to compile the custom components before displaying them?
app.js:
App = Ember.Application.create();
var g1 = "{{#my-bold}}Yo{{/my-bold}}, {{#my-italic}}dude{{/my-italic}}!";
var g2 = "<b>Yo</b>, <i>dude</i>!";
App.IndexRoute = Ember.Route.extend({
model: function() {
return {greeting1: g1, greeting2: g2}
}
});
App.MyBoldComponent = Ember.Component.extend({tagName: "span"});
App.MyItalicComponent = Ember.Component.extend({tagName: "span"});
index.html
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" id="components/my-bold"><b>{{yield}}</b></script>
<script type="text/x-handlebars" id="components/my-italic"><i>{{yield}}</i></script>
<script type="text/x-handlebars" id="index">
<ol>
<li>{{model.greeting1}}</li>
<li>{{{model.greeting1}}}</li>
<li>{{{model.greeting2}}}</li>
<li>{{#my-bold}}Yo,{{/my-bold}} {{#my-italic}}dude!{{/my-italic}}</li>
</ol>
</script>
output:
{{#my-bold}}Yo{{/my-bold}}, {{#my-italic}}dude{{/my-italic}}!
{{#my-bold}}Yo{{/my-bold}}, {{#my-italic}}dude{{/my-italic}}!
Yo, dude!
Yo, dude!
From the Ember.js issue tracker https://github.com/emberjs/ember.js/issues/11649 on dynamically inserting components:
This isn't something we support, I also suspect we won't as it would require all of the htmlbars compiler client side and would likely be pretty slow. If you wish to add components dynamically. The component helper may be your best bet.
On that issue they are proposing to use the {{component}} helper, but that doesn't work with your code since you actually want to produce two component.
They are also talking about the RFC for contextual components: https://github.com/emberjs/rfcs/pull/64#issuecomment-111761176 which depending on their implementation would work similar to what you're doing. So what can you do?
As far as I can tell it's simply not possible to do with 1.13 (I tried quite a number of things) because rerender doesn't work, but they are going to fix it. If you downgrade to 1.12 you can do:
App.RenderTemplateComponent = Ember.Component.extend({
layout: function(){
return Ember.Handlebars.compile(this.get('templateString'));
}.property('templateString')
});
Then in your template something like:
{{render-template templateString="test {{x-foo}} {{x-foo}}"}}
Take a look at this JSFiddle:
http://emberjs.jsbin.com/jazayiyufi/1/edit?html,css,js,output
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},
);