Reducing code duplication in Ractive.js - javascript

I'm running into the issue that many different pages on my website (created using Ractive.js) need the same functions, mostly functions that perform AJAX calls back to the server. I would normally store all these functions in one JS file and include it in all of my pages for common functionality, but when I do this the function aren't recognized inside my Ractive code for the individual pages.
So it looks something like this
<script src="src/to/common/library"></script>
<div id="target"></div>
<div id="template">
// Ractive code
load_models(); // defined in common library, throws error that it's not defined.
</div>

I figured it out. Instead of doing
$(function() {
var MAIN = new Ractive({
el: '#target',
template: '#template',
I can just do
$.getScript("/app_name/static/js/scripts/common.js", function() {
var MAIN = new Ractive({
...
)};
// all functions defined in common.js are available for your use now
});

Related

Why does v-if not get affected when the data is updated later?

If I were to create an element such as that below:
<div id="helloWorldDiv" v-if="visible">
Hello World
</div>
and then create a Vue instance for it:
var helloWorld = new Vue({
el: "#helloWorldDiv",
data: {
visible: false
}
});
I would expect that the line 'helloWorld.visible = true;' would show the element, but it has not effect. Can anyone explain why this doesn't work?
JSFiddle
I think you are getting started with Vue.js, which is great!
There are several changes you need to do in your sample app. Check this fiddle: https://jsfiddle.net/mani04/f20Ld806/
As you can see in that example, your show() function needs to be defined inside the methods of your Vue app. Also the show button needs be part of the app template, not outside of it.
You can find a lot more in Vue docs and tutorials online.
First off, I would suggest not manipulating the Vue instance from the outside. It'll make it harder to maintain the app as it grows.
However, as to your question, there's a number of issues with your JSFiddle:
You never set visible to true.
In your show function, you misspelled helloWorld as helloWolrd.
The show function and helloWorld variable need to be attached to the window so they can be globally accessed from the onclick event.
So if you update your javascript to:
var helloWorld = new Vue({
el: "#helloWorldDiv",
data: {
visible: false
}
});
function show() {
helloWorld.visible = true;
};
window.helloWorld = helloWorld;
window.show = show;
Your code works as expected.

handlebar compilation errors

Hi I have been trying to use backbonejs and handlebar templates but seems like either my jSON is wrong or data is not properly parse . Getting
Uncaught Error: You must pass a string to Handlebars.compile. You passed undefined
Code can be found at
jsfiddle
any advice will be appreciated
Your fiddle is broken in various ways but the odds are that you're doing this:
template: Handlebars.compile($('#tpl-page-list-item').html()),
before there is a #tpl-page-list-item available. This will happen if your page looks like:
<script src="your_backbone_javascript.js"></script>
<script id="tpl-page-list-item" ...></script>
as your Backbone view will be parsed before <script id="tpl-page-list-item"> gets added to the DOM. You can wrap your Backbone views in a document-ready handler (with proper namespacing to account for the function wrapper):
$(function() {
window.PageListItemView = Backbone.View.extend({
template: Handlebars.compile($('#tpl-page-list-item').html()),
//...
});
});
or compile the template when instantiating your view:
initialize: function() {
// Or check if it is in the prototype and put the compiled template
// in the prototype if you're using the view multiple times...
this.template = Handlebars.compile($('#tpl-page-list-item').html());
//...
}

Verbose Logging in Ember

I'm trying to wrap my head around Ember at the moment, but all the magic is making this difficult.
I've set LOG_TRANSITIONS: true and Ember.LOG_BINDINGS = true; which gives me some minimal logging to the console, but I really need more than that.
I'm particularly struggling with seeing what's going on when Ember is automagically creating Controllers, Views and Templates.
Is there a way to log this aspect of the framework - to see where Ember is looking for Templates/Views/Controllers and when it is creating one on its own volition.
For example, I have the following routes set up:
App.Router.map(function() {
this.route("example_items", {path: "/"});
});
with:
App.ExampleItemsRoute = Ember.Route.extend({
model: function() {
return App.ExampleItem.find();
}
});
Ember renders my ApplicationController and its application.handlebars template:
<header class="page-header">
<h1>Application Template</h1>
</header>
{{outlet}}
But fails to render my example_items.handlebars template. I get no exception or warning, and if I check the DOM, I can see ember has created a generic view in its place.
The bindings logging shows me that Ember has transitioned to example_items, but it seems it hasn't used either my ExampleItemsController, ExampleItemsView or template.
How can I debug a situation like this if I receive no errors or messages?
Edit:
App.ExampleItems View:
App.ExampleItemsView = Ember.CollectionView.extend({
templateName: 'example_items'
});
And App.ExampleItemsController:
App.ExampleItemsController = Ember.ArrayController.extend({
});
I'm particularly struggling with seeing what's going on when Ember is automagically creating Controllers, Views and Templates.
Is there a way to log this aspect of the framework - to see where Ember is looking for Templates/Views/Controllers and when it is creating one on its own volition.
Yes. With the latest ember you can now LOG_ACTIVE_GENERATION to see console.log output whenever ember generates something for you.
Another new setting that might be helpful is LOG_VIEW_LOOKUPS
Here's your problem: CollectionView won't use your template. It takes an array as its content property (usually set up as a binding to the controller) and creates childViews manually. Without a content set it'll appear as a blank view.
If you add classNames: ['my-view'] to your view definition, you should see that the view it's instantiating and inserting is actually your view class, just empty. Add contentBinding: 'controller' and it should render itemViews for each item in the array, as well.

Referencing Backbone views from app view

Hey all I am pretty new to Backbone though I have put several days into trying to get familiar with this framework, and it seems everytime I start feeling comfortable I run across a new problem.
I am wondering how to reference a view that is rendered from within my main appview. I know this is a really simple issue but I just can't seem to figure it out.
So for instance I have a simple view
var SubView = Backbone.View.extend({
//something here including render function
});
Then I render that view from within the main app view
var myApp = Backbone.View.extend({
render: function{
var mysubView = new SubView();
mysubView.render();
},
editSomething: function{
mysubView.remove();
}
});
When I try and reference that view from a function (editSomething:) in the main app view, I get a reference error.
What I am trying to achieve is that I have two views that include forms. I want to swtich between the two forms as an edit function is called and when an add function is called. But I can't seem to access the views that have already been rendered.
I don't want to initialize and render a new view before removing the existing view because from what I understand, I will start to get a bunch of views floating in memory.
Reference it using this:
var myApp = Backbone.View.extend({
render: function{
this.subView = new SubView();
this.subView.render();
},
editSomething: function{
this.subView.remove();
}
});

How do I create multi-page applications with Meteor?

I am new to Javascript and just started fiddling around with Meteor out of curiosity. What really surprises me, is that it seems that all HTML content gets combined into a single page.
I suspect there is a way to introduce some handling of URLs directing to special pages. It seems that the "todo" example is capable of doing this via some kind of Router class. Is that the "canonical" way of URL handling?
Assuming I can handle URLs, how would I structure my HTML code to display separate pages? In my case they could each have completely separate sets of data, so no HTML code needs to be shared at all.
Jon Gold's answer used to be correct, but as of Meteor 0.5.4:
Work has now shifted to Iron Router. Please consider using IR instead of Router on new projects!
Thus, the current "canonical" way to do this is probably to use IronRouter.
As far as I am aware, there is currently no out of the box way to do this.
What I suggest to do, is to use Backbone.js smart package.
Backbone.js comes with the push-state Router, and if the user's browser doesn't support that it will fallback to hash urls.
In your meteor app directory type this meteor add backbone.
Then somewhere in your client-side code create a Backbone.js Router like so:
var Router = Backbone.Router.extend({
routes: {
"": "main", //this will be http://your_domain/
"help": "help" // http://your_domain/help
},
main: function() {
// Your homepage code
// for example: Session.set('currentPage', 'homePage');
},
help: function() {
// Help page
}
});
var app = new Router;
Meteor.startup(function () {
Backbone.history.start({pushState: true});
});
Then somewhere in your Handlebars template, you can create a helper that will render a page based on the value set in Session's "currentPage".
You can find more information about backbone.js router here: http://backbonejs.org/#Router
Also relevant information on how to create a Handlebars helper method in Metoer here: http://docs.meteor.com/#templates
Hope this helps.
Meteor-Router makes this really easy. I've been using it in some apps I've been building with Telescope as a good reference. Have a look at Telescope's router.js
To use it…
mrt add router
In client/router.js:
Meteor.Router.add({
'/news': 'news', // renders template 'news'
'/about': function() {
if (Session.get('aboutUs')) {
return 'aboutUs'; //renders template 'aboutUs'
} else {
return 'aboutThem'; //renders template 'aboutThem'
}
},
'*': 'not_found'
});
In your template…
<body>{{renderPage}}</body>
I found the same problem. When the code gets bigger it is difficult to keep the code clean.
Here goes my approach to this problem:
I separate the different html pages as I would do with another web framework. There is an index.html where I store the root html page. And then for each big functional part I create a different template and place it in one different html. Meteor then merges them all. Finally I create a session variable called operation where I define what to show at each time.
Here goes a simple example
index.html
<head>
<title>My app name</title>
</head>
<body>
{{> splash}}
{{> user}}
{{> debates}}
</body>
then in splash.html
<template name="splash">
{{#if showSplash}}
... your splash html code goes here...
{{/if}}
</template>
then in user.html
<template name="user">
{{#if showUser}}
... your user html code goes here...
{{/if}}
</template>
and so on ...
In the javascript code then I check when to print each template using the Session variable, like this:
Template.splash.showSplash = function(){
return Session.get("operation") == 'showSplash';
}
Finally the Backbone Router manages this Session variable
var DebateRouter = Backbone.Router.extend({
routes: {
"": "showSplash",
"user/:userId": "showUser",
"showDebates": "showDebates",
// ...
},
splash: function () {
Session.set('operation', 'showSplash');
this.navigate('/');
},
user: function (userId) {
Session.set('operation', 'showUser');
this.navigate('user/'+userId);
},
// etc...
});
I hope this pattern is helpful for other Meteor developers.
This is my hacky solution to routing :
https://gist.github.com/3221138
Just put the page name as the template name en navigate to /{name}

Categories