Formatting live template variables in WebStorm - webstorm

I have a live template for creating directives in angular, and one of the things I'd like to do to make it easier to use is copy the dependency array in the controller declaration for the directive into the parameters for the controller function. The problem is that the dependency array requires the parameters to be strings, so one might look like ['$scope', '$location', 'etcService', controllerName] where the parameters are everything in the array before the controller name. The controller function where I want to inject those parameters would be function controllerName($scope, $location, etcService){}
In order to do this you can see I need to remove the quotes around each array element. Is this possible to do in live templates?
Here is my current template:
(function () {
'use strict';
var app = angular.module('$moduleName$');
app.controller('$controllerName$', [$PARAMS$, $controllerName$]);
app.directive('$directiveName$', function () {
return {
templateUrl: 'app/$templateUrl$',
transclude: $transclude$,
restrict: '$restrict$',
scope: $scope$,
controller: $controllerName$
}
});
function $controllerName$($PARAMS_noQuotes$){
$END$
}
})();

Unfortunately it's not possible using Live Templates as it has no "replace" functions that would allow replacing characters (in your case: ' by nothing) to do your desired transformation.
I have not found any dedicated ticket where such functionality is requested; only partially related comments here or another partially related ticket.
It definitely makes sense to submit separate ticket (Feature Request) -- much better chance that particular functionality will be implemented sooner (and will not get lost): https://youtrack.jetbrains.com/issues/WEB

It is possible to achieve such functionality with predefined function groovyScript. It is documented only briefly: https://www.jetbrains.com/idea/help/live-templates-2.html but it is an alternative for more complicated live template manipulation.
Let's define the simplified live template named 'ctrl':
app.controller('$controllerName$', [$PARAMS$, $controllerName$]);
function $controllerName$($PARAMS_noQuotes$){
$END$
}
Variables for the live template could look like this (notice that PATH_TO_GROOVY_SCRIPT have to be manually exchanged to full path to groovy script!):
Live template scripts can be stored as scratches:
In this case "PATH_TO_GROOVY_SCRIPT" would be:
"<YOUR_INTELLIJ_HOME>\\config\\scratches\\Live Templates\\ctrl\\PARAMS_noQuotes.groovy"
Actual script can be very simple e.g.:
"$_1".replaceAll("'","")
In my opinion even in such a simple case it is a good practice to use separate script files instead of inline script expression in variable dialog. Separate scripts have this advantage they can be easily tested in Groovy Console...
Ready template can be used like this:

I'm not sure where it was implemented, but as of not it's possible to replace any string using regular expressions with
regularExpression(<String>, <Pattern>, <Replacement>)
See https://www.jetbrains.com/help/idea/template-variables.html#predefined_functions

Related

Rendering from strings instead of files with MarkoJS

I'm using markojs for my emails templates but now we are moving these templates inside our database to edit them online.
We still need to use marko to keep our full HTML structure and variables behavior aswell.
I've found 2 ways to get templates as string like renderSync() method but it need the template to exist as file before or with compile() but I don't know how to make it work with variables handling.
You can use Marko's load method to compile templates and get back the template instance which you can then render to get the final HTML:
const template = require("marko").load(templatePath, templateSource, compilerOptions);
const html = template.renderSync(data);
You probably don't need to pass any custom compilerOptions and can omit the last argument.
Even though your template doesn't exist on disk, you still need to pass a templatePath to a real directory with a dummy .marko file. For instance you could do this:
const templatePath = path.join(__dirname, `${database.id}.marko`);
The templatePath is used for two purposes:
As a key for node's require cache. If you request to compile the same filename multiple times, you will get the original compilation. This might mean you need to purge the require cache when a template is edited: delete require.cache[templatePath];
To discover custom Marko tags. If you have custom tags/components that are intended to be used by the email templates, you should make sure that the path specified by templatePath allows those tags to be discovered.

Ember App Kit - Which way to register Handlebars Helper

Over at the Ember App Kit website one can see two methods to create Handlebars helper methods where the first one (can be seen here) uses the following steps:
export default a function which takes two arguments and dasherize
the file name so that it could be found by the ember-jj-abrams
resolver.
import the function/file in app.js and call Ember.Handlebars.registerBoundHelper to register the helper
function.
The second one (could be seen here) uses a different way, where you export default the whole function wrapped in the Ember.Handlebars.makeBoundHelper function which is documented to be
...(mostly) private helper function to registerBoundHelper. Takes the
provided Handlebars helper function fn and returns it in wrapped bound
helper form.
The main use case for using this outside of registerBoundHelper is for
registering helpers on the container...
Find it at the Ember Documentation here.
So, as I interpret the documentation, if I use the second method I would have to register the helper in the container within an Ember.initializer in app.js, am I right? Is there any difference so that one would prefer one over the other?

Confusion about "data-template-name" and "id" in "<script>" tag

After <script type="text/x-handlebars"
a. I'm wondering in what cases do I put data-template-name and what cases do I put id.
In the guide tutorial video source they use ids exclusively.
In the todomvc source and pretty much everywhere else I've seen, data-template-name is used.
b. And what exactly is put after data-template-name and id (i.e. what comes after their =)?
a) AFAIK id is the newer version of data-template-name, and they seem to work the same.
b) The id allows you to identify a template it in your routing, rendering or 'views'.
For Routing:
You can use this name to help the router identify which template to render, e.g. use this.render('displayStuff) during the renderTemplate in a route, to "override" the default template that belongs to the route.
See also: http://emberjs.com/guides/routing/rendering-a-template/
For Rendering:
Templates allow specific ways to change rendering. Ember-Handlebars provides {{render}} and {{partial}} to change the default template associated to the view.
See also: http://emberjs.com/guides/templates/rendering-with-helpers/
For Views:
By default, a view will find its corresponding template based on convention. So the somethingView has an associated somethingController and a something template (so template with id='something'). A view will also allow to forgo this convention by setting its templateName parameter.
See also: http://emberjs.com/guides/views/inserting-views-in-templates/
hope it helps!
Both work and are correct but data-template-name has a higher precedence and gives you more freedom re: element id's (they wont conflict with template ids)
via http://discuss.emberjs.com/t/ember-components-id-or-data-template-name-in-handlebars-script-tag/3847
also when you move your handlebars templates to stand alone files (production situation lets say) you won't need to worry about id vs data-template-name (let your build tools do this for you based on the template file name)

Emberjs - unable to redefine named, explicitly compiled Handlebars template

As part of an attempt to port a fairly large/complex existing application to the Ember world, I'm generating and compiling named Handlebars templates dynamically, and associating views with them, using the technique:
var template = Ember.Handlebars.compile("some handlebars stuff");
Ember.TEMPLATES["myTemplate"] = template;
var view = Ember.View.create({
templateName: "myTemplate"
});
One of the things I'd like to do is be able to recompile new/different Handlebars template markup which overwrites the template named "myTemplate" and have it be accessible to views at that name.
I'm getting unexpected results trying to do this - a couple fiddles that illustrate the problems:
First fiddle - Shows what happens if you wait before rendering a view after the named template contents have changed.
Second fiddle - Shows what happens if there's no delay before rendering a view after the named template contents have changed.
There's obviously some magic under the hood that I'm not understanding. Can anyone shed some light on this?
UPDATE:
I went through the source code for Ember.View and the container module, and came to realize that I could solve the problem in the First fiddle by overriding the "template" computed property in a way that skips the container cache lookup. I've put up another fiddle here to demonstrate the solution I found.
This seems to be working the way I'd like it to - but - it feels like I might be fighting with the framework and "unhooking" from the container in a way that might bite me later. Is there a better, more Ember-esque way to accomplish what I'm trying to do? Will the hack I found break things?
UPDATE 2
I've also discovered that it's also possible to simply call
view2.get('container').reset();
before appending view2 in the First fiddle. Seems cleaner/safer, but is it "legal"? I've updated the First fiddle to illustrate this.
(in the second fiddle, both views show the second template)
This is because view1.appendTo($("#target")); just schedules the append, actual view rendering does not happen until end of the run loop. Before that happens, you've set Ember.TEMPLATES["myTemplate"] = template2;
(in the first fiddle, both views show the first template)
Pretty sure this is because ember container caches template fx, but not 100% on that. Checking...
I'm going to call this one answered. As I mentioned in my second comment, I'm using the solution shown in this fiddle in my project, along these lines:
mYiew.get('container').reset();
There's some discussion about the container not being intended to be used as an API here: https://github.com/emberjs/ember.js/commit/5becdc4467573f80a5c5dbb51d97c6b9239714a8 , but there doesn't seem to be any mention of using the container from Views for other use cases.
Also, a View's container can be accessed directly (at ".container") - meaning the devs haven't made it "hard" to get to the way they have for an Application's ".__ container __". This might suggest something about how they intend it to be used.
Since a View having the ability to clear its cache whenever it wants to doesn't seem to me to be unreasonable or a bad practice, I'm using the above mentioned solution...at least until someone sets me straight with a better idea (or a cache API).

ember js compare values in DOM if statement or at least in a View with value from DOM

I been trying to compare some values in handlebars if statement {{#if value == 'otherValue'}}, obviously unsuccessfully because handlebars do not like this and expecting a string, boolean, or function name. Well that would be ok, but then I tried to pass parameter in the function like you can do with {{action}} helper, and well that didn't workout either, got this in console
Error: assertion failed: You must pass exactly one argument to the if helper
So then I decided to do this in a View, even so ember js guides points that accessing template values in-scope is unusual and they provide only poor paragraph with no examples.
http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_accessing-template-variables-from-views
So when I tried to do this, I got a problem of accessing those variables, I tried this way this.get('controller.templateVariables') and via full path to View, but value was either undefined or .get() wasn't exists as a method.
So at this moment I decided to save variable in the DOM data property, but turns out this {{#view App.TabsView data-title="{{tab}}"}} is going to literately give me a string {{tab}} when I try to access it from View with this.get('data-title').
The only way left to me was to insert additional element inside view and store variable there, and afterwards access it with jQuery class selector. but element is not yet exist in the DOM at the time of isVisible function gets executed, so I have no access to values at that time. That explains why this.get('element') was returning null.
Similar examples on ember js mostly ends up with something like if (someLogic) {}, but how I can do any logic when there is no variables available to me.
Question
To simplify my question - is there a way how I can do such a thing in ember js? Simple as
// have objects stored in controller
var obj = [{title:'Tab1'}, {title:'Tab2'}, {title:'Tab3'}];
// loop via them in the DOM
obj.forEach(function(tab) {
// do this kind of comparison
if( tab.title == currentTab() ) {
// do something here
}
});
If that is not possible, then what would be the other way to achieve similar functionality?
You can write a handlerbar helper to do this
{{activeTab tab}}
Handlebars.registerHelper('activeTab', function(tab) {
})
See a question about the same issue
Active Tab
Or look at existing helpers to write your own
Bind Helper
Template Helper
I think the best way for me to demonstrate this is with a heavily commented JSFiddle that I've put together for you: http://jsfiddle.net/PbLnm/
Please ask any questions below if you're not sure about anything.
The main part which determines when to add the active class is in the computed property:
// Determine if the object we have for this view is the same as the activeTab's object. If it is the same, then this view is the current active tab.
active: function() {
return Boolean(this.get('parentView.activeTab') == this.get('tab'));
}.property('parentView.activeTab')