Way to organize client-side templates into individual files? - templating

I'm using Handlebars.js, and currently all my templates live inside script tags which live inside .html files housing dozens of other templates, also inside script tags.
<script type="text/template" id="template-1">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-2">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-3">
<div>{{variable}}</div>
</script>
...
Then I include this file on the server-side as a partial.
This has the following disadvantages:
A bunch of templates are crammed into HTML files.
Finding a given template is tedious.
I'm looking for a better way to organize my templates. I'd like each each template to live in its own file. For example:
/public/views/my_controller/my_action/some_template.html
/public/views/my_controller/my_action/some_other_template.html
/public/views/my_controller/my_other_action/another_template.html
/public/views/my_controller/my_other_action/yet_another_template.html
/public/views/shared/my_shared_template.html
Then at the top of my view, in the backend code, I can include these templates when the page loads, like this:
SomeTemplateLibrary.require(
"/public/views/my_controller/my_action/*",
"/public/views/shared/my_shared_template.html"
)
This would include all templates in /public/views/my_controller/my_action/ and also include /public/views/shared/my_shared_template.html.
My question: Are there any libraries out there that provide this or similar functionality? Or, does anyone have any alternative organizational suggestions?

RequireJS is really good library for AMD style dependency management. You can actually use the 'text' plugin of requireJS to load the template file in to your UI component. Once the template is attached to the DOM, you may use any MVVM, MVC library for bindings OR just use jQuery events for your logic.
I'm the author of BoilerplateJS. BoilerplateJS reference architecture uses requireJS for dependency management. It also provides a reference implementations to show how a self contained UI Components should be created. Self contained in the sense to handle its own view template, code behind, css, localization files, etc.
There is some more information available on the boilerplateJS homepage, under "UI components".
http://boilerplatejs.org/

I ended up using RequireJS, which pretty much let me do this. See http://aaronhardy.com/javascript/javascript-architecture-requirejs-dependency-management/.

I use a template loader that loads the template using ajax the first time it is needed, and caches it locally for future requests. I also use a debug variable to make sure the template is not cached when I am in development:
var template_loader = {
templates_cache : {},
load_template : function load_template (params, callback) {
var template;
if (this.templates_cache[params.url]){
callback(this.templates_cache[params.url]);
}
else{
if (debug){
params.url = params.url + '?t=' + new Date().getTime(), //add timestamp for dev (avoid caching)
console.log('avoid caching url in template loader...');
}
$.ajax({
url: params.url,
success: function(data) {
template = Handlebars.compile(data);
if (params.cache){
this.templates_cache[params.url] = template;
}
callback(template);
}
});
}
}
};
The template is loaded like this:
template_loader.load_template({url: '/templates/mytemplate.handlebars'}, function (template){
var template_data = {}; //get your data
$('#holder').html(template(template_data)); //render
})

there's this handy little jquery plugin I wrote for exactly this purpose.
https://github.com/cultofmetatron/handlebar-helper

Related

vue.js how to pass data to root element

I'm currently building an application using a dotnet core backend and some Vue.js elements in the front. I was able to build the application using regular Vue (non template, plain non es6 javascript syntax) in a cshtml file, but I've been trying to move towards a more modular structure using vue components in .vue files.
The problem I'm running into is that in the original version, I would have access to Json objects when instantiating the root element:
var jsonRenderedWithHtml = #Html.Raw(Json.Serialize(Model.SomeJsonObject));
vm = new Vue({
el: "#root-element",
data: {
vueData: jsonRenderedFromHtml;
}, ...
When I switch over to the component version, from what I've found, I need to render the root element from a javascript file, doing something like this:
import RootElement from "../Vue/RootElement.vue";
import Vue from 'vue';
let vm = new Vue({
el: '#root-element',
render: h => h(RootElement)
});
Then, I would import this script in the #section Scripts part of the cshtml file. Unfortunately, from within the javascript file, there doesn't seem to be a way to pass in data from outside (from the cshtml file). It seems that if I were to instead write an AJAX request inside the vue root instance, it would need to do two server requests to do the same job.
It also seems that I can't use import statements within cshtml (don't seem to be any webpack loaders for cshtml?). Otherwise, I would skip rendering the element in a separate javascript file.
What we did in our application was to output the data added to the ViewData into the view through as json into a script tag and added an object to the window in the script with the previously rendered json. In the beforeCreate we then read the data from the object we added to the window and commit it to our store. Something like:
#{
IHtmlString myObj = null;
if(ViewData["SomeObject"] is ContentResult)
myObj = Html.Raw(((ContentResult)ViewData["SomeObject"]).Content);
<script type="text/javascript">
(function(){
window.obj = JSON.parse(myObj);
});
</script>
You could however add a prop to your App and pass the object in through the prop just create your vue instance in a script tag.

Where are #Json.Encode or #Json.Decode methods in MVC 6?

What is equivalent of MVC5's #Json.Encode method in MVC6? In MVC5 we can access those methods in views. But I can't find any methods which I can access from MVC 6 views.
I don't want to write a helper method if there is already a built in feature in MVC6.
After some search, found it:
#inject IJsonHelper Json;
#Json.Serialize(...)
I've had success with the following:
#Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(myObj) as String)
I'm not sure if Json.Encode has made it in yet because it was a part of System.Web which is gone now.
One of the features of #Json.Encode() was automatic HTML encoding of entities within JSON strings, which is helpful to avoid XSS vulnerabilities. The JsonHelper class is based on Json.NET serialization now, which does support at least some (or all) of this same functionality if configured properly. The other solutions here can be vulnerable to XSS attacks if untrusted data is serialized.
Quick example of a vulnerability:
<script>
window.something = #Json.Serialize(new { someprop = "Hello</script><script>alert('xss')</script><script>" });
</script>
Will be rendered as
<script>
window.something = {"someprop":"Hello
</script>
<script>alert('xss')</script>
<script>"};</script>
To properly configure Json.NET to escape HTML entities would be to use the #Json.Serialize(object, serializerSettings) overload and override StringEscapeHandling to EscapeHTML. The settings could be defined in a helper class or injected.
#using Newtonsoft.Json
<script>
#{
var settings = new JsonSerializerSettings {StringEscapeHandling = StringEscapeHandling.EscapeHtml};
}
window.something = #Json.Serialize(new { someprop = "Hello</script><script>alert('xss')</script><script>" }, settings);
</script>
Which is rendered instead as:
<script>
window.something = {"someprop":"Hello\u003c/script\u003e\u003cscript\u003ealert(\u0027xss\u0027)\u003c/script\u003e\u003cscript\u003e"};
</script>
Some other methods of safely serializing data to the page in ASP.NET Core can be found here: https://github.com/aspnet/Docs/blob/master/aspnetcore/security/cross-site-scripting.md

jquery ui of drupal not working

Version Drupal 7.16
I'm trying to use draggable of jquery in Drupal way :
I have a simple page (with hook_menu) wich call an js and render a simple div with the good class to draggable :
(function($) {
Drupal.behaviors.testJs = {
attach : function(context, settings) {
$('.test-js').draggable();
});
}
}
})(jQuery);
This js is load.
I add library of jquery Drupal :
drupal_add_library('system', 'ui');
or
drupal_add_library('system', 'ui.draggable');
But nothing happen....
When I had an external jquery like :
drupal_add_js('http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js', 'external')
draggable work.
I try to enable jquery update module, but nothing more....
It is most likely that the hook you are calling isn't called int the right order. template_process_html is where css and js are finalized and rendered to template variables. Try adding your code in hook_preprocess_html and see if that works. Otherwise find a hook that is called before template_process_html like hook_init. If that doesn't work give a more detailed code sample of how you are trying to achieve this.
https://api.drupal.org/api/drupal/includes%21theme.inc/function/template_process_html/7
https://api.drupal.org/api/drupal/modules%21system%21theme.api.php/function/hook_process_HOOK/7
https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme/7
https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_init/7

Jquery calls not working in $viewContentLoaded of Angular

Unable to call jquery functions in $viewContentLoaded event of Angular controller, here is the code for the same.
$scope.$on('$viewContentLoaded', function() {
jQuery.growlUI('Growl Notification', 'Saved Succesfully');
jQuery('#category').tree()
});
Is any configuration required here?? I tried even noConflict(); var $jq = jQuery.noConflict();
Does it require any other configuration?
Thanks,
Abdul
First thing first, don't do DOM manipulation from controller. Instead do it from directives.
You can do same thing in directive link method. You can access the element on which directive is applied.
Make sure you load jquery before angularjs scripts, then grawlUI, three, angularJS and finally your application script. Below is directive sample
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
$.growlUI('Growl Notification', 'Saved Succesfully');
element.tree();
};
});
angularjs has built in jQuery lite.
if you load full jquery after angular, since jQuery is already defined, the full jquery script will skip execution.
==Update after your comment==
I reviewed again your question after comment and realised that content which is loaded trough ajax is appended to some div in your angular view. Then you want to apply element.tree() jquery plugin to that content. Unfortunately example above will not work since it is fired on linking which happened before your content from ajax response is appended to element with directive I showed to you. But don't worry, there is a way :) tho it is quick and dirty but it is just for demo.
Let's say this is your controller
function ContentCtrl($scope, $http){
$scope.trees=[];
$scope.submitSomethingToServer=function(something){
$http.post("/article/1.html", something)
.success(function(response,status){
// don't forget to set correct order of jquery, angular javascript lib load
$.growlUI('Growl Notification', 'Saved Succesfully');
$scope.trees.push(response); // append response, I hope it is HTML
});
}
}
Now, directive which is in controller scope (it uses same scope as controller)
var app = angular.module("someModule", []);
app.directive("myDirective", function () {
return function (scope, element, attrs) {
scope.$watch("trees", function(){
var newParagraph=$("<p>" + scope.trees[scope.trees.length-1] + "</p>" ); // I hope this is ul>li>ul>li...or what ever you want to make as tree
element.append(newParagraph);
newParagraph.tree(); //it will apply tree plugin after content is appended to DOM in view
});
};
});
The second approach would be to $broadcast or $emit event from controller (depends where directive is, out or in scope of controller) after your ajax completes and you get content from server. Then directive should be subscribed to this event and handle it by receiving passed data (data=content as string) and do the rest as I showed you above.
The thing is, threat that content from ajax as data all the way it comes to directive, then inject it to element in which you want to render it and apply tree plugin to that content.

call custom js function in UIWebView

I'm trying to pre fill in fields to log in to a forum. However, I don't own the forum. So how do I link my own .js file so that I can fire a function that will pre fill the log in fields?
(Remember I don't own the servers that host the html files, so I cannot hook it up via HTML.)
You can inject your own javascript into a page being displayed by a UIWebView by
1) Put your javascript into a file in your app bundle, for example something like this will inject myFunction().
var script = document.createElement('script');
script.type = 'text/javascript';
script.text = function myFunction()
{
alert("my function");
};
document.getElementsByTagName('head')[0].appendChild(script);
2) Load the .js file and run it using stringByEvaluationJavaScriptFromString:
3) If its important your myFunction() doesn't get added until the dom has loaded, then within the same .js file add some other JavaScript that will ensure that the code in part 1) doesn't get run until you get a dom loaded event.
cross domain javascript fails everytime.
use ajax to retrieve the page you wish.
$(document).ready(function(){
jQuery.ajax(’forumlogin’).done(function(data)
{
$(’body’).html(data)
})
})
then fill in the forms using the forms element.

Resources