Extend / override Meteor blaze template from packages - meteor

I use the useraccounts:ionic package and I would like to add a line to the beginning of one of its templates.
I know that I can get the repo from GitHub and then use it in my project, but I would rather keep using it through "meteor add".
Is it possible to change or "override" individual templates?

A couple of options for you:
Check out the 'aldeed:template-extension' package; it exports a 'replaces(templateName)' method that will do what you want.
Implement your own override method like this:
//
// Helper shim to override template renderFunctions
// Inspired by replaces() from aldeed:template-extension package. Good stuff.
Template.prototype._override = function (replacement){
if (typeof replacement === 'string') {
replacement = Template[replacement];
}
if (replacement && replacement instanceof Blaze.Template ) {
this.renderFunction = replacement.renderFunction;
}
}
...
Template.someTemplateILike._override('myReplacementTemplate');
--
kobi

Related

What is 'Template.instance().view'?

I read [Template.instance().view]1 at Blaze docs.
Also I read Blaze.view().
I even saw the view object in the console log.
But I can't understand.
Could anyone explain it more intuitively and smoothly, please? :)
If you want to understand Views more deeply, you need to understand the relationship between Templates, TemplateInstances, and Views. Views are just reactive parts of the DOM. Template instances contain one View, but templates can create more views through functions that create renderable content like Blaze.with ({{#with}}) or Blaze.if ({{#if}}). These "child" views will will then store a parent pointer, which you can use to reconstruct the View tree.
What might help your understanding is playing around with how Templates and Views interact in Chrome tools. You can find a template instance by using any DOM element. Here is an example to get you started:
templateInstance = Blaze.findTemplate($('<some component in dom>')[0])
view = templateInstance.view
You can extend Blaze to contain findTemplate like this:
Blaze.findTemplate = function(elementOrView) {
if(elementOrView == undefined) {
return;
}
let view = Object.getPrototypeOf(elementOrView) === Blaze.View.prototype
? elementOrView
: Blaze.getView(elementOrView);
while (view && view.templateInstance === undefined) {
view = view.originalParentView || view.parentView;
}
if (!view) {
return;
}
return Tracker.nonreactive(() => view.templateInstance());
};

Displaying dynamic content in Meteor using Dynamic Templates

I've read through the (somewhat sparse) documentation on Dynamic Templates but am still having trouble displaying dynamic content on a user dashboard based on a particular field.
My Meteor.users collection includes a status field and I want to return different content based on this status.
So, for example , if the user has a status of ‘current’, they would see the 'currentUser' template.
I’ve been using a dynamic template helper (but have also considered using template helper arguments which may still be the way to go) but it isn’t showing a different template for users with different statuses.
{{> Template.dynamic template=userStatus}}
And the helper returns a string to align with the required template as required
userStatus: function () {
if (Meteor.users.find({_id:Meteor.userId(), status: 'active'})){
return 'isCurrent'
}
else if (Meteor.users.find({_id:Meteor.userId(), status: ‘isIdle'})) {
return 'isIdle'
} else {
return ‘genericContent'
}
}
There may be much better ways to go about this but it seems a pretty common use case.
The few examples I've seen use Sessions or a click event but I’d rather use the cursor if possible. Does this mean what I’m missing is the re-computation to make it properly reactive? Or something else incredibly obvious that I’ve overlooked.
There is a shortcut for getting the current user object, Meteor.user(). I suggest you get this object and then check the value of the status.
userStatus: function () {
if(Meteor.user()) {
if (Meteor.user().status === 'active') {
return 'currentUserTemplate'; // this should be the template name
} else if (Meteor.user().status === 'isIdle') {
return 'idleUserTemplate'; // this should be the template name
}
} else {
return ‘notLoggedInTemplate'; // this should be the template name
}
}
Ended up using this approach discussed on the Meteor forums which seems a bit cleaner.
{{> Template.dynamic template=getTemplateName}}
And the helper then becomes:
getTemplateName: function() {
return "statusTemplate" + Meteor.user().status;
},
Which means you can then use template names based on the status:
<template name="statusTemplateActive">
Content for active users
</template>
(though keep in mind that Template helpers don't like hyphens and the data context needs to be set correctly)

Check if element has class only with Jasmine test framework

I am using webdriverJS and Jasmine to perform an end-to-end testing of a web page. I would like to test if an element has class under certain circumstances, but I would like to do it using methods from pure jasmine.
This is the part of the code where the issue is located:
describe('Header bar', function() {
it('should show/hide elements accoding to the window position', function() {
this.driver.executeScript('scroll(0, 1000)');
var elemSearch = this.driver.findElements(webdriver.By.id('animatedElement, animatedElement2, animatedElement3'));
expect(elemSearch).toContain('appear-2');
});
})
Do you know if there's a way to solve this issue, or a couple of examples I could look at, without using extensions like jasmine-jquery?
Thanks in advance for your replies!
If you don't want having jasmine-jquery or other third-party packages introducing custom jasmine matchers as a dependency, you can always extract the toHaveClass() matcher implementation and use it. Note that having your assertion logic encapsulated inside custom matchers helps to follow the DRY principle and make your tests cleaner.
FYI, here is toHaveClass implementation we are currently using:
beforeEach(function() {
jasmine.addMatchers({
toHaveClass: function() {
return {
compare: function(actual, expected) {
return {
pass: actual.getAttribute("class").then(function(classes) {
return classes.split(" ").indexOf(expected) !== -1;
})
};
}
};
},
});
});

(AngularJS) Only one less file for entire Website

I am a beginner with AngularJS and I have a little problem, I installed grunt-contrib-less to support less files instead css but now I have to declare all less styles that will be compiled into only one css file.
But my problem is normally when I'm using less, I write some code for a specific page, and here I have to write the style code for all pages. This is confusing and not really maintanable so is there a best practice to organize less styles?
I tought that there may be multiple solution:
Apply a class to body tag and change it with I don't know what
(controller, services or other)
(Import LESS file only for one page)
Generate multiple css file depending which style is compiled (but I can't do this because I can't configure grunt correctly)
Do this with DOM manipulation (but it don't find it beautifull because I think Angular must have a good way to solve that problem)
Could you explain me how to have different style for differents views ? I don't want to have the same style for all links in all views and without create hundreds classes I don't know how to do that.
Use directive
and add whatever variables/code/logic you want to add
HTML template(directive) of style can be added to your view and after compile you will get different ui for all your views
for reference read
angular directive
I solve my problem by adding specific class on body tag depending the route.
I put a variable in rootScope called 'pageStyle' with correspond to the classname that I want. This variable is updated automatically when route change (see run function). There is an event when the route change ($stateChangeSuccess or $routeChangeSuccess depending if you are using ngRoute or -angularui-routeur).
In my case i would like to add the name of the route but you can do it with the controller name or something else.
Here is an example
This is the routes :
angular
.module('frontApp', [])
.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider, $mdThemingProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: '../views/home.html',
controller: function ($scope) {
$scope.msg = 'Xavier';
}
})
.state('form', {
url: '/form',
templateUrl: '../views/form.html',
controller: 'FormCtrl'
});
}])
And in the run function you will see the event bound to adapt the class when route change :
.run(function($rootScope) {
$rootScope.pageStyle = '';
// Watch state and set controller name in pageStyle variable when state change
$rootScope.$on('$stateChangeSuccess', function(event, toState) {
event.preventDefault();
if (toState && toState.name && typeof toState.name === 'string'){
$rootScope.pageStyle = toState.name;
} else {
$rootScope.pageStyle = '';
}
});
});
Extra informations :
Note that the event called when route change is different if you are using ngroute. use "$routeChangeSuccess" if you use ngRoute and "$stateChangeSuccess" if you choose to use angular-ui-routeur
If you want to add the controller name instead the route name simply use the follow and replace 'ctrl' with you controller suffixe:
if (toState && toState.controller && typeof toState.controller !== 'function'){
$rootScope.pageStyle = toState.controller.toLowerCase().replace('ctrl','');
}
Hope it help someone else

How can I access the name of the current route in meteor when using meteor-router?

I'm building an app using meteor and meteor router, and I would like to make a template helper for checking if the route is a specific one ({{#ifRouteIs login}}{{/ifRouteIs}}).
I had the same issue. Building on your answer, I found a working solution. It needs to go in the client side of Meteor.
Handlebars.registerHelper('ifRouteIs', function (routeName, options) {
if (Meteor.Router.page() === routeName) {
return options.fn(this);
}
return options.inverse(this);
});
According to meteor-router's README, you can get the current page with Meteor.Router.page(), so the helper might look like this:
Handlebars.registerHelper('ifRouteIs', function (routeName) {
return Meteor.Router.page() === routeName;
});

Resources