Web-resources from Javascript - handlebars.js

I need to get handlebars templates in Javascript.
So I create template file in tpl folder and wrote such line in ML:
<resource type="download" name="tpl/" location="/tpl"/>
if I put some image to this folder I can to get it from CSS:
.css
{
background: url(tpl/image.png);
}
if I want to get this image from js AJS.$("css").css("background", "url(tpl/image.png)") I have the error - file not found;
image file is for example.. In real I need to get template
AJS.$.ajax({
url: "tpl/backlog_coll.handlebars",
cache: true,
success: function(data) {
source = data;
template = Handlebars.compile(source);
$('#backlog_coll').html(template);
}
});

Here's how I would do that
I will write a function in a generally accessible js file (lets call it Global.js for now) as shown below
GLOBAL.JS
function fnGetTemplate(strName) {
if (Handlebars.templates === undefined || Handlebars.templates[strName] === undefined) {
$.ajax({
url : "tpl" + strName + ".handlebars",
success : function(data) {
if (Handlebars.templates === undefined) {
Handlebars.templates = {};
}
Handlebars.templates[strName] = Handlebars.compile(data);
},
async : false
});
}
return Handlebars.templates[strName];
}
This is assuming I have the handlebars js library (something like handlebars-v1.3.0.js) referred to appropriately.
Then inside the View where I need the template to show up, I would declare the template as shown below
template: fnGetTemplate("backlog_coll");
Inside the render function of my view I would call this template supplying the needed data as show below
render: function() {
this.$el.html(this.template(data));
}
Hope this helps

Related

How to set file name and extension to the original when inserting a file with full url or URI in CollectionFS?

Model code:
ProfileImage = new FS.Collection('profileImage', {
stores: [
new FS.Store.FileSystem('profile-image')
],
filter: {
maxSize: 524288,
allow: {
extensions: ['png', 'jpg', 'jpeg'],
contentTypes: ['image/png', 'image/jpg', 'image/jpeg']
}
}
});
Insertion code:
ProfileImage.insert('http://graph.facebook.com/' + user.services.facebook.id + '/picture/?type=large', function(error, imageObj) {
console.log(imageObj);
});
with that code I get a file name like this: profileImage-iiGE2ouSifuu3iLjq-undefined .
the name is undefined and without extension at all.
Try this (copied from a project of mine. this works):
//this is the event for when you select an image
'change .yourfileinput': function (event, template) {
FS.Utility.eachFile(event, function (file) {
var yourFile = new FS.File(file);
Images.insert(yourFile, function (err, fileObj) {
var fileUrl = '/cfs/files/profile-image/'+fileObj._id;
Session.set('fileUrl', fileUrl);
});
});
},
//form submit event
"submit .your-form-class": function (event) {
var whichUser = Meteor.userId() //or you could just write this inside the method call instead of adding a variable
var profilePicture = Session.get('fileUrl');
Meteor.call("yourMethod", whichUser, profilePicture);
}
Of course, you need to play on it/customise to your needs. ^ is for default file path of cfs:filesystem.
I switched to gridfs though and I highly recommend it.
Edit your question with all your code if it doesn't work and we'll find a solution. File upload was the biggest problem I encountered along the way.

Server side rendering with Meteor and Meteorhacks:ssr and iron-router

This came out recently: https://meteorhacks.com/server-side-rendering.html but there doesn't seem to be a full fledged example of how to use this with iron-router.
If I had a template like:
/private/post_page.html
{{title}}
{{#markdown}} {{body}} {{/markdown}}
How would I populate it with a single records attributes from a request for a specific ID ?
E.g page requested was localhost:3000/p/:idofposthere how to populate it with data and render it in iron-router for that route / server side?
Actually a bit easier than you think (I just followed Arunoda's SSR example and converted it to iron-router for you):
if(Meteor.isServer) {
Template.posts.getPosts = function(category) {
return Posts.find({category: category}, {limit: 20});
}
}
Router.map(function() {
this.route('home');
this.route('view_post', {
path: 'post/:id',
where:"server",
action : function() {
var html = SSR.render('posts', {category: 'meteor'})
var response = this.response;
response.writeHead(200, {'Content-Type':'text/html'});
response.end(html);
}
});
});
It only gets tricky if you share the same route for client and server side for example, if you want it to render client-side based on user agent.
Source: We use this strategy on our own apps.
UPDATE
While the above code is simply what the question is asking for, we can get this working to follow Google's Ajax spec by checking the ?_escaped_fragment_= query string before we reach the client..
Basically, what we mostly don't know about Iron-Router is that if you have identical routes declared for server and client, the server-side route is dispatched first and then the client-side.
Here's the main javascript (with annotations):
ssr_test.js
Router.configure({
layout: 'default'
});
Posts = new Mongo.Collection('posts');
// Just a test helper to verify if we area actually rendering from client or server.
UI.registerHelper('is_server', function(){
return Meteor.isServer ? 'from server' : 'from client';
});
myRouter = null;
if(Meteor.isServer) {
// watch out for common robot user-agent headers.. you can add more here.
// taken from MDG's spiderable package.
var userAgentRegExps = [
/^facebookexternalhit/i,
/^linkedinbot/i,
/^twitterbot/i
];
// Wire up the data context manually since we can't use data option
// in server side routes while overriding the default behaviour..
// not this way, at least (with SSR).
// use {{#with getPost}} to
Template.view_post_server.helpers({
'getPost' : function(id) {
return Posts.findOne({_id : id});
}
});
Router.map(function() {
this.route('view_post', {
path: 'post/:id', // post/:id i.e. post/123
where: 'server', // this route runs on the server
action : function() {
var request = this.request;
// Also taken from MDG's spiderable package.
if (/\?.*_escaped_fragment_=/.test(request.url) ||
_.any(userAgentRegExps, function (re) {
return re.test(request.headers['user-agent']); })) {
// The meat of the SSR rendering. We render a special template
var html = SSR.render('view_post_server', {id : this.params.id});
var response = this.response;
response.writeHead(200, {'Content-Type':'text/html'});
response.end(html);
} else {
this.next(); // proceed to the client if we don't need to use SSR.
}
}
});
});
}
if(Meteor.isClient) {
Router.map(function() {
this.route('home');
this.route('view_post', { // same route as the server-side version
path: 'post/:id', // and same request path to match
where: 'client', // but just run the following action on client
action : function() {
this.render('view_post'); // yup, just render the client-side only
}
});
});
}
ssr_test.html
<head>
<title>ssr_test</title>
<meta name="fragment" content="!">
</head>
<body></body>
<template name="default">
{{> yield}}
</template>
<template name="home">
</template>
<template name="view_post">
hello post {{is_server}}
</template>
<template name="view_post_server">
hello post server {{is_server}}
</template>
THE RESULT:
I uploaded the app at http://ssr_test.meteor.com/ to see it in action, But it seems to crash when using SSR. Sorry about that. Works fine if you just paste the above on Meteorpad though!
Screens:
Here's the Github Repo instead:
https://github.com/electricjesus/ssr_test
Clone and run!
SSR is lacking real life examples, but here is how I got it working.
if (Meteor.isServer)
{
Router.map(function() {
this.route('postserver', {
where: 'server',
path: '/p/:_id',
action: function() {
// compile
SSR.compileTemplate('postTemplate', Assets.getText('post_page.html'));
// query
var post = Posts.findOne(this.params._id);
// render
var html = SSR.render('postTemplate', {title: post.title, body: post.body});
// response
this.response.writeHead(200, {'Content-Type': 'text/html'});
this.response.write(html);
this.response.end();
}
});
});
}
Assets are documented here: http://docs.meteor.com/#assets.

Letting a user use a compiled RequireJS Widget after it has loaded

I'm writing a JS Widget using RequireJS. After finishing the widget I'm compiling it with r.js and Almond. All goes well - but I couldn't find an easy way to let the user use the widget without using RequireJS himself - as the widget code loads async (RequireJS uses AMD).
What I'm doing now is busy waiting for the widget code to load and using it only after detecting it has loaded. This is not very user-friendly.
Is there a way to let just do something like this?
var widget = new Widget();
instead of doing busy wait like:
count = 0;
function loadWidget() {
if (typeof Widget != 'undefined') {
var p1 = new Widget();
p1.render();
} else {
if (count > 10) {
console.log('Failed to load the Widget');
return false;
}
setTimeout(loadWidget, 50);
count++;
}
}
$(document).ready(function() {
loadWidget();
});
Thanks!
EDIT:
my build.js
({
name: './lib/almond.js',
out: './deploy/sdk.min.js',
baseUrl: '.',
optimize: 'uglify2',
mainConfigFile: 'sdk.js',
include: ['sdk'],
wrap: true
})
Code on the web page (assume no other script tags on page):
<script src="mywidget.js" data-main="scripts/sdk" id="mywidget"></script>
No sure if the 'data-main' is really required as the js is compiled.
You need to follow the instructions provided with Almond. To summarize the essential points what is in the doc there, what you need in your build config the following configuration:
wrap: {
startFile: 'path/to/start.frag',
endFile: 'path/to/end.frag'
}
And the start.frag should be:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else {
root.Widget = factory();
}
}(this, function () {
and the end.frag:
return require('main');
}));
The end fragment calls require in its synchronous form, which is really synchronous in this case (and not the pseudo-synchronous sugar that can be used by RequrieJS itself).
I've tried this before. It works.

meteorjs iron-router waitOn and using as data on rendered

I try to get the returned data in my Template.rendered function.
The current code is:
this.route('editCat', {
layoutTemplate : 'layoutCol2Left',
template : 'modCategoriesEdit',
path : '/mod/categories/edit/:_id',
yieldTemplates : _.extend(defaultYieldTemplates, {
'navigationBackend' : {to : 'contentLeft'}
}),
waitOn : function () {
return Meteor.subscribe('oneCat', this.params._id);
},
data : function () {
return Categories.findOne({_id : this.params._id});
}
});
In this block i wait on the subscribtion of the Collection Document and return the Document as data.
Now i can use the returned Document in my Template like this:
<template name="modCategoriesEdit">
<h1>Edit {{name}}</h1>
</template>
My problem is that i have to use the returned data in my rendered function like this:
Template.modCategoriesEdit.rendered = function () {
console.log(this.data);
}
But this returns "null".
So my question is:
How is it possible to get access to the returned data in the rendered function ?
Solution:
Just add the following to your iron-router route() method.
action : function () {
if (this.ready()) {
this.render();
}
}
Than the Template will rendered after all is loaded correctly.
There are 3 solutions if you want to wait until the waitOn data is ready before rendering:
1- Add an action hook to each route
Router.map(function()
{
this.route('myRoute',
{
action: function()
{
if (this.ready())
this.render();
}
}
}
2- Use the onBeforeAction hook globally or on every route
Sample code for the global hook:
Router.onBeforeAction(function(pause)
{
if (!this.ready())
{
pause();
this.render('myLoading');
}
});
myLoading (or whatever name) must be a template you have defined somewhere.
Don't forget the this.render line, otherwise the problem will occur when leaving the route (while the original problem occurs when loading the route).
3- Use the built-in onBeforeAction('loading') hook
Router.configure(
{
loadingTemplate: 'myLoading',
});
Router.onBeforeAction('loading');
myLoading (or whatever name) must be a template you have defined somewhere.
Using the action hook to check for this.ready() works, but it looks like the official way to do this is to call the following:
Router.onBeforeAction("loading");
Reference: https://github.com/EventedMind/iron-router/issues/679
Like #Sean said, the right solution is to use a loading template:
Router.onBeforeAction("loading");
But if you don't want it, like me, I came up with this solution:
Template.xxx.rendered = function() {
var self = this;
this.autorun(function(a) {
var data = Template.currentData(self.view);
if(!data) return;
console.log("has data! do stuff...");
console.dir(data);
//...
});
}
Template.currentData is reactive, so in the first time it is null and in the second it has your data.
Hope it helps.
-- Tested on Meteor v1.0 with Iron Router v1.0

How to attach element to another Ajax component

All, Forgive me I am not familiar with the ASP.NET Ajax. I knew the method Create is attaching an html element to ajax component. But I don't know how to detach it from the current component . and attach another one.
Let's say there is a element ctl00_PlaceHolderMain_UserRegistration_txbPassword1 has been attached to a component type AccelaWebControlExtender.HelperBehavior, and the created component id is ctl00_PlaceHolderMain_UserRegistration_txbPassword1_helper_bhv. The code looks like below. please review it .
Sys.Application.add_init(function() {
$create(AccelaWebControlExtender.HelperBehavior, {"closeTitle":"Close","id":"ctl00_PlaceHolderMain_UserRegistration_txbPassword1_helper_bhv","isRTL":false,"title":"Help"}, null, null, $get("ctl00_PlaceHolderMain_UserRegistration_txbPassword1"));
});
I think firstly I should retrieve the component by id, then do the detach and attach work. Hope someone can give me some help.Thanks.
After doing some research, I found It is called Extend Web server control that encapsulates a client behavior in Asp.net Ajax, And I found the attachment of component is done by Asp.net automatically . We can see the Sys.Application.add_init(function() code is generated in the aspx page by Asp.net automatically. So if we want to customize the original behavior of Web Server Control, I believe it can be made in the Javascript OOP way(old and same).
For example :
If the original behavior code is blow.
// Register the namespace for the control.
Type.registerNamespace('Samples');
//
// Define the behavior properties.
//
Samples.FocusBehavior = function(element) {
Samples.FocusBehavior.initializeBase(this, [element]);
this._highlightCssClass = null;
this._nohighlightCssClass = null;
}
//
// Create the prototype for the behavior.
//
Samples.FocusBehavior.prototype = {
initialize : function() {
Samples.FocusBehavior.callBaseMethod(this, 'initialize');
$addHandlers(this.get_element(),
{ 'focus' : this._onFocus,
'blur' : this._onBlur },
this);
this.get_element().className = this._nohighlightCssClass;
},
dispose : function() {
$clearHandlers(this.get_element());
Samples.FocusBehavior.callBaseMethod(this, 'dispose');
},
//
// Event delegates
//
_onFocus : function(e) {
if (this.get_element() && !this.get_element().disabled) {
this.get_element().className = this._highlightCssClass;
}
},
_onBlur : function(e) {
if (this.get_element() && !this.get_element().disabled) {
this.get_element().className = this._nohighlightCssClass;
}
},
//
// Behavior properties
//
get_highlightCssClass : function() {
return this._highlightCssClass;
},
set_highlightCssClass : function(value) {
if (this._highlightCssClass !== value) {
this._highlightCssClass = value;
this.raisePropertyChanged('highlightCssClass');
}
},
get_nohighlightCssClass : function() {
return this._nohighlightCssClass;
},
set_nohighlightCssClass : function(value) {
if (this._nohighlightCssClass !== value) {
this._nohighlightCssClass = value;
this.raisePropertyChanged('nohighlightCssClass');
}
}
}
// Optional descriptor for JSON serialization.
Samples.FocusBehavior.descriptor = {
properties: [ {name: 'highlightCssClass', type: String},
{name: 'nohighlightCssClass', type: String} ]
}
// Register the class as a type that inherits from Sys.UI.Control.
Samples.FocusBehavior.registerClass('Samples.FocusBehavior', Sys.UI.Behavior);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
I think we can override some of the methods of the Javascript Object Samples.FocusBehavior and it's prototype object to achieve customization.
For example .
I can override Samples.FocusBehavior.prototype._onFocus in the script like this.
Samples.FocusBehavior.prototype._onFocus = function (e) {
alert('test');
if (this.get_element() && !this.get_element().disabled) {
this.get_element().className = this._highlightCssClass;
}
};
Just make sure this code is parsed after original one by Browser.
I am not sure if this is the right way to make it . I hope someone can help to verify it .Thank you very much.
Here is a tutorial of it. please review it .
Cheers.

Resources