compiling a template into a string in angular without a directive - javascript

I'm trying to add some html into a tinyMCE textarea (tinyMCE can show html inside those editable textareas while allowing the user to manipulate them live).
So, lets say my template is:
var template = '<span>hello {{ user.name }}</span>'
I'm trying to:
compile the template with the current controller's scope.
stringify it into a varialbe (after it was compiled)
concat it to the end of the tinyMCE editor.
my controller's code is:
// [...]
var user = {};
user.name = "john";
$scope.user = user;
$templateRequest('<PATH_TO_TEMPLATE>').then(function() {
var linkingFunc = $compile(template);
// if I understand correctly, this should replace the user.name with "john"
var parsedTemplate = linkingFunc($scope);
console.log(parsedTemplate.prop('outerHTML'));
});
// [...]
The output of parsedTemplate.prop('outerHTML') is:
<span>hello {{ user.name }}</span>
Does it get rendered only if I inject it to the DOM after linking it to the scope?
is there a way to get it compiled in the javascript without rendering it back?
I'm trying to get some sort of var templateWITHOUTVariables which will euqal <span>hello john</span>
any ideas?
thanks!

Thanks to #FrailWords, I solved this using $timeout.
So my code looks like this:
var user = {};
user.name = "john";
$scope.user = user;
$templateRequest('<PATH_TO_TEMPLATE>').then(function() {
var parsedTemplate = $compile(template)($scope); // at this point, the template isn't processed yet
//timeout in order to get the template processed
$timeout(function() {
console.log(parsedTemplate.prop('innerHTML');
})
});
output:
<span>hello john</span>
When the $timeout executes, the $digest process already finished processing the parsedTemplate.

Related

Pug call js function from another file inside template

I can't solve this for almost four hours, and i can't find any helpful documentation for this kind of problems. This is the issue, I'm using pug/jade templates and i want to call function inside pug template to transform some data
This is the main template:
/** main template */
section
each pet in pets
.pet
.photo-column
img(src= pet.photo)
.info-column
h2= pet.name
span.species= (pet.species)
p Age: #{calculateAge(pet.birthYear)} //here I need to call calculateAge function
if pet.favFoods
h4.headline-bar Favorite Foods
ul.favorite-foods
each favFood in pet.favFoods
li!= favFood
/** end main template **/
This is the external function:
/** calculateAge.js **/
module.exports = function(birthYear) {
var age = new Date().getFullYear() - birthYear;
if (age > 0) {
return age + " years old";
} else {
return "Less than a year old";
}
};
/** end calculateAge.js **/
What shell I do to make this happen?
There may be better way to handle this, but I usually do it by importing the external module and then passing it as part of template context object. That means the code that renders the template should be something like:
const calculateAge = require("calculateAge"); // change path accordingly
router.get("/main", function(){
let pageInfo = {};
pageInfo.title = "Demo";
pageInfo.calculateAge = calculateAge;
res.render("main", pageInfo);
});
Now, you can access calculateAge in your template. If this module is used a lot in most of the templates, then you should pass it as part of res.locals or app.locals so that it is available for all templates without the need to append it for every path request.
In PUG options use locals property to import functions you want to use inside your templates.
const calculateAge = require('./calculate-age');
const config = {
pug: {
locals: {
calculateAge,
},
},
};
Then you can use it in all your templates like this (please note the extra unescaping tag !{}):
p Age: !{calculateAge(pet.birthYear)}
Like in raw HTML if you want JS to execute in a sepcific part you need a script tag to enclose the js you want to use.
span.species= (pet.species)
p Age:
.script
calculateAge(pet.birthYear)
if pet.favFoods
Make your function available in pug like this:
//assuming you're using express
app.set('view engine', 'pug');
app.locals.someFunction = input => input * 5;
// or
import {someOtherFunction} from "packageOrFile";
app.locals.someOtherFunction = someOtherFunction;
In your pug you then can do
span= someFunction(10)
span= someOtherFunction(123)
This is basically what mahish wrote in his comment, but it actually answers the question satisfactory and here's the documentation.
You can write javascript with .script tag
script.
$( document ).ready(function() {
calculateAge(params)
})

Angular Translate synchronicity issue in JS

Angular Translate works great as a filter in the view.
I am using angular-translate-loader-static-files with external files like locale-en.json etc.
The problem is when I try to do something like this:
var placeholder = $translate('placeholder.NAME')
.then(function (translatedValue) {
return translatedValue;
});
I always get a promise back, and in the UI it shows as {} instead of the word NAME for english etc.
What is the correct way to translate in JS using angular-translate?
EDIT:
Tried this and got the following result (still not solved)
var placeholder = '';
$translate('placeholder.NAME').then(function (translatedValue) {
console.log(translatedValue);
placeholder = translatedValue;
}, function(err){
console.log(err); // returns placeholder.NAME
});
console.log(placeholder); // returns empty string
var placeholder = '';
$translate('placeholder.NAME').then(function (translatedValue) {
placeholder = translatedValue;
});
I'd recommend to keep your controller free from translation logic and translate your strings directly inside your view like this:
<h1>{{ 'TITLE.HELLO_WORLD' | translate }}</h1>
You can use instant function to get the value without the promise:
var translation = $translate.instant('placeholder.NAME');
However, this does not wait for the translation files to get loaded. You should make sure you are calling this after translation files are loaded.
From the website http://angular-translate.github.io/docs/#/guide/03_using-translate-service635
app.controller('Ctrl', ['$scope', '$translate', function ($scope, $translate) {
$translate(['HEADLINE', 'PARAGRAPH', 'NAMESPACE.PARAGRAPH']).then(function (translations) {
$scope.headline = translations.HEADLINE;
$scope.paragraph = translations.PARAGRAPH;
$scope.namespaced_paragraph = translations['NAMESPACE.PARAGRAPH'];
});
}]);

Issue with subscriptions on multiple instances of a template

Here is the scenario. I have a template that contains a #each loop and renders an instance of a particular template, setting the data context on each template as per the docs.
<template name = 'live'>
<div class = 'row'>
{{#each runways}}
<div class = 'col-md-2'>
{{> runway_panel}}
</div>
{{/each}}
</div>
</template>
And this is the helper backing it:
Template.live.helpers({
runways: function(){
return Runway_Data.find();
}
});
This works, my issue is as follows. Each live_event_log instance has a template level subscription that subscribes to a publication that takes the _id parameter of the data context, like so:
Template.runway_panel.onCreated(function(){
var instance = this;
instance.autorun(function(){
var subscription = instance.subscribe('runway_status', this.data._id);
});
instance.status = function(){
return Runway_Status.find();
}
});
This is the publication:
Meteor.publish('runway_status', function(runway){
if(this.userId){
//Retrieve the last know status for the given runway
return Runway_Status.find({runway: runway});
}
});
This is when it all falls apart, I get this on the browser console:
[Log] Exception in queued task: http://localhost:3000/client/views/live/runway_panel.js?4efaac87b39527d3dfd3d65a174520f9bce3c565:4:73 (meteor.js, line 888)_withTemplateInstanceFunc#http://localhost:3000/packages/blaze.js?a5c324925e5f6e800a4c618d71caf2848b53bf51:3476:16
http://localhost:3000/packages/blaze.js?a5c324925e5f6e800a4c618d71caf2848b53bf51:1864:54
_withCurrentView#http://localhost:3000/packages/blaze.js?a5c324925e5f6e800a4c618d71caf2848b53bf51:2197:16
As soon as I comment out the subscription line everything else works, am I missing something really obvious here? Could it have something to do with multiple subscriptions to the same publication?
Thank you! :)
SOLUTION
Thanks to Jeremy S. input and some sleep after a night shift i've finally figured it out without an autorun. So here it goes for posterity:
Template.runway_panel.onCreated(function(){
var self = this;
self.subscribe('runway_status', this.data._id);
});
Should probably have tried getting some sleep before trying again!
The problem is with this.data._id in your subscription, which right now is scoped to the innermost function. You want instance.data._id (which is nonreactive so you wouldn't need an autorun) or Template.currentData() (which is reactive).
Template.runway_panel.onCreated(function(){
var instance = this;
instance.autorun(function(){
var data = Template.currentData();
var subscription = instance.subscribe('runway_status', data._id);
});
});
Also note that in your publication, you should mark it as this.ready() if this.userId is undefined. But that's not the source of the error.
First, userId is a function and userId() would return current user id. And you could check here to learn more detail of instance.subscribe.
I think your problem may happen in getting runway._id in Meteor.publish
Template.runway_panel.onCreated(function(){
var instance = this;
// instance subscribe data whose _id is runwayPanelId
instance.autorun(function(){
var dataContext = Template.currentData();
var subscription = instance.subscribe('runway_status', dataContext.runwayPanelId);
});
instance.status = function(){
return Runway_Status.find();
}
});
// publication
Meteor.publish('runway_status', function(runway){
// using Meteor.userId() to get current user id
if(Meteor.userId()){
//Retrieve the last know status for the given runway
return Runway_Status.find({runway: runway});
}
});
<template name = 'live'>
<div class = 'row'>
{{#each runways}}
<div class = 'col-md-2'>
{{> runway_panel runwayPanelId=_id}}
</div>
{{/each}}
</div>
</template>

HTML view cannot see AngularJS

I am making a backend call using AngularJS using AJAX. My call returns the JSON successfully. This code is written in a JavaScript file.
I have a html file in the same code base which is unable to iterate through this JSON.
My JavaScript snippet is as below:
angular.module('kmapp').controller("FieldCodesCtrl", ['$scope', function($scope){
var model = {};
console.log("FieldCodesCtrl");
$http.get("/my/rest/URL").success(function (data) {
model.items = data;
console.log("data set on items");
$scope.fieldCodes = model;
console.log($scope.fieldCodes.items.length);
});
// $scope.fieldCodes = model;
}]);
My html is as below:
<tr ng-repeat="item in fieldCodes.items">
<td>{{item.id}}</td>
<td>{{item.comment}}</td>
</tr>
My issue is that the "fieldCodes.items" has nothing in the html. So it does not display the ID and Comment that I get from my JSON.
Can someone please help. I am new to AngularJS. So please excuse me if it is something obvious.
Instead of using model.items = data; , Use model = data; Otherwise it will not defined properly. As you are using in your view (model bind) item.id looks ok. so try with this (model = data) Hope this will work. I can Answer you more specify, If you can sent the sample JSON.
Thanks
\Riyadh
$http needs to be injected into your controller.
.controller("FieldCodesCtrl", ['$scope', '$http', function($scope, $http){
Make sure you have your module registered to the HTML tag in the document. I think it is something like "ng-app."
Maybe I'm looking at this wrong, but it seems that you are assigning this object to model.items
{ fieldCodes: {
items: [
{ id: XXX name: CCC value: DD comment: AA },
{ id: aaaa name: aaaaadd value: ddf comment: ee }]
}
}
Wouldn't you instead want model = data.fieldCodes; to be able to use fieldCodes.items?

Compiling an Ember template with specified values

I need to get a template from Ember.TEMPLATES, compile it with a specified object and get its raw HTML value.
Ember.TEMPLATES content (generated using gruntjs) returns a function and seems to be already passed through Handlebars.template() function so for example I would have this:
Ember.TEMPLATES["test"] = Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) {
this.compilerInfo = [4,'>= 1.0.0'];
helpers = this.merge(helpers, Ember.Handlebars.helpers); data = data || {};
var buffer = '', hashTypes, hashContexts, escapeExpression=this.escapeExpression;
data.buffer.push("<strong>hello world ");
hashTypes = {};
hashContexts = {};
data.buffer.push(escapeExpression(helpers._triageMustache.call(depth0, "test", {hash:{},contexts:[depth0],types:["ID"],hashContexts:hashContexts,hashTypes:hashTypes,data:data})));
data.buffer.push("</strong>\n");
return buffer;
});
and would like to compile that template with new values from a JSON object.
I tried something like that based on what I've seen in Ember code:
var test = Ember.TEMPLATES['test'];
var compiled = test({ test: 'value' });
I thought it might work but it doesn't actually.
Basically I'd like to do like with standard handlebars :
Handlebars.compile('<strong>{{hello}}</strong>', { hello: 'world' });
Is there any way to compile a template with specified values, and get the HTML result using Emberjs?
Ember do some modifications in handlebars compiler to enable the use of computed properties, make templates update when model changes etc.
If you see the view render method, it does more than template(context), it use the context and some private custom data. So Handlebars.compile is diferent of Ember.Handlebars.compile and I think that compiled templates from Ember.Handlebars.compile, is not intended to be used outside of a Ember.View.
Marking script types with text/x-raw-handlebars, instead of text/x-handlebars make the template be compiled with Handlebars.compile.
The following sample will work, but without the ember features:
Template
<script type="text/x-raw-handlebars" data-template-name="custom-template">
First name: {{firstName}} <br/>Last name: {{lastName}}
</script>
Javascript
App = Ember.Application.create({
ready: function() {
var template = Ember.TEMPLATES['custom-template'];
var html = template({ firstName: 'Tom', lastName: 'Dale' });
$('body').append(html);
}
});
You can see this sample here http://jsfiddle.net/marciojunior/MC8QB/

Categories

Resources