I am using sammy for a web application that needs to render templates stored inline in the page. I am using a script tag to contain the markup, which is haml.
Is there a good, idiomatic way to render templates that are not loaded via ajax request? I have a solution, but I am not happy with it. $('#start_haml') is the script element containing the markup and $('#sammy_main') is the container to render into.
app.get '#/', (context) ->
context.load($('#start_haml')).then((data) ->
context.interpolate(data, {helpers: view_helpers})
).replace('#sammy_main')
Thanks to Aaron Quint for answering me on the Sammy.js mailing list
The answer is simple, but worth leaving here since it is not mentioned in the documentation.
context.render($('#start_haml'), {helpers: view_helpers})
.replace '#sammy_main'
NB. The second parameter to render() is the view data.
For me, this worked:
this.use('Template', "[object HTMLScriptElement]"); // If not view data are not rendered
[...]
var template = $('#tmpInmuebleDetalle')[0];
this.partial(template);
Related
Ok, this idea might seem quite a bit crazy and it kindo' is (at least for me at my level).
I have a fairly standarad rails app (some content pages, a blog, a news block, some authentication). And I want to make it into a single page app.
What I want to accomplish is:
All the pages are fetched through AJAX like when using turbolinks, except that the AJAX returns only the view part (the yield part in the layout) withought the layout itself, which stays the same (less data in the responces, quicker render and load time).
The pages are mostly just static html with AngularJS markup so not much to process.
All the actual data is loaded separately through JSON and populated in the view.
Also the url and the page title get changed accordingly.
I've been thinking about this concept for quite a while and I just can't seem to come up with a solution. At this point I've got to some ideas on how this actualy might be done along with some problems I can't pass. Any ideas or solutions are greatly appreciated. Or might be I've just gone crazy and 3 small requests to load a page are worse then I big that needs all the rendering done on server side.
So, here's my idea and known problems.
When user first visits the app, the view template with angular markup is rendered regularly and the second request comes from the Angular Resource.
Then on ngClick on any link that adress is sent to ngInclude of the content wrapper.
How do I bind that onClick on any link and how can I exclude certain links from that bind (e.g. links to external authentication services)?
How do I tell the server not to render the layout if the request is comming from Angular? I though about adding a parameter to the request, but there might be a better idea.
When ngInclude gets the requested template, it fires the ngInit functions of the controllers (usually a single one) in that template and gets the data from the server as JSON (along with the proper page title).
Angular populates the template with the received data, sets the browser url to the url of the link and sets the page title to what it just got.
How do I change the page title and the page url? The title can be changed using jQuery, but is there a way through Angular itself?
Again, I keep thinking about some kind of animation to make this change more fancy.
Profit!
So. What do you guys think?
OK, in case enyone ever finds this idea worth thinking about.
The key can be solved as follows.
Server-side decision of whether to render the view or not.
Use a param in the ngInclude and set the layout: false in the controller if that param is present.
Have not found an easier way.
Client-side binding all links except those that have a particular class no-ajax
Here's a directive that does it.
App.directive('allClicks', function($parse) {
return {
restrict: 'A',
transclude: true,
replace: true,
link: function(scope, element, attrs) {
var $a = element.find('a').not($('a.no-ajax')),
fn = $parse(attrs['allLinks']);
$a.on('click', function(event) {
event.preventDefault();
scope.$apply(function() {
var $this = angular.element(event.target);
fn(scope, {
$event: event,
$href: $this.attr('href'),
$link: $this
});
});
});
}
};
})
And then use it on some wrapper div or body tag like <body ng-controller="WrapperCtrl" all-links="ajaxLink($href)"> and then in your content div do <div id="content" ng-include="current_page_template">
In your angular controller set the current_page template to the document.URL and implement that ajaxLink function.
$scope.ajaxLink = function(path) {
$scope.current_page_template = path+"?nolayout=true";
}
And then when you get your JSON with your data from the server don't forget to use history.pushState to set the url line and document.title = to setr the title.
I have a partial view that I have included on my _Layout.cshtml. It simply has a javascript function that changes an image based on the state of my system. I don't need to reload any data, I don't need to go to the code of the controller for anything, I simply need to reload that partial view.
I tried many of the examples that I found here but couldn't get any of them to work. I felt as if they were too complex for what I was doing anyway. Any guidance would be appreciated.
Thanks,
Steve
If the partial is loaded into the layout directly then there's no straightforward way to refresh it, because it's basically a part of the complete rendered page.
Your best bet is to render the partial using $.load or whatever equivalent you have available by hitting a controller method and rendering the result into a container (like a div). You would have to do this within a script that is loaded with the layout itself, by observing document.ready or something like that. Once you have that in place then it's trivial to keep reloading or refreshing the contents by hitting the controller method as many times as you need. For example in jQuery:
$(document).ready(function () {
RefreshPartial();
window.setInterval(RefreshPartial, 10000);
});
function RefreshPartial() {
$('#container').load('/some/controller/endpoint', {parameters});
}
This will call the controller method, and set the inner contents of the element identified with #container. You can call RefreshPartial as many times as you want.
Partial views only exist on the server. The only way to "refresh" the partial is to go back to the server to get it again.
Obviously, you must be doing something in the partial that needs refreshing. Whatever that is, should be callable from javascript to do the refresh.
I'd like to use razor syntax inside my Javascript files. Is this possible without including the javascript inline into the page?
I found a razor engine RazorJS on nuget that solves # in js files
The owner blog and explanations about the package abilities
The Nuget package
see more in this question
The Razor engine only runs against the page, not any included javascript files.
You could write a custom parser that will run the view engine against any javascript files before serving them, and I imagine any attempt to do so would be a very useful open source project.
However, the simplest solution that comes to mind (if these variables are not sematically linked to any DOM elements) is to simply declare and initialise your variables in the page (or in an included partial page) and your javascript (in .js files) relies on these variables being defined.
If however the variables that you require are logically associated with DOM elements, I prefer to use data-* attributes to define these, this way your javascript can be consumed by the html, rather than the other way around. For example, if you have a content area that should be automatically updated by javascript (using jQuery as an example here):
HTML:
<div data-auto-refresh="pathToContent" data-auto-refresh-milliseconds="1000"></div>
Javascript:
$(function() {
$('[data-auto-refresh]').each(function() {
var self = $(this);
var url = self.data('auto-refresh');
var interval = self.data('auto-refresh-milliseconds');
// Code to handle refresh here ...
});
});
You can set the value in hidden field in yout cshtml file , and then in your javascript files you can access the hidden field.
I have a table in my db where one of the properties is an Html page (without the html, head and body tags), and I intend to put it in the middle of one of my views - say, I call a cotroller method that takes an argument, and return a view passing this html big string as the model. I searched for it (not much, I admit), and found the following method:
<%= System.Web.HttpUtility.HtmlDecode(yourEncodedHtmlFromYouDatabase) %>
That was found here in stackoverflow. When I tried a similar razor aproach, I ended up with this:
#System.Web.HttpUtility.HtmlDecode("<h1>Test</h1>")
That's the idea, but it didn't work quite as I planned.
All you need is: #Html.Raw(yourEncodedHtmlFromYouDatabase)
I'm assuming that the html in the database has been properly sanitized (or at least from a reliable source), because if not, you could be opening yourself up to cross-site scripting attacks.
The reason your approach didn't work is that Razor HTML-encodes output by default (every time you use # to display something). Html.Raw tells Razor that you trust the HTML and you want to display it without encoding it (as it's already raw HTML).
You can also return a HTMLString and Razor will output the correct formatting, for example.
#Html.GetSomeHtml()
public static HtmlString GetSomeHtml()
{
var Data = "abc<br/>123";
return new HtmlString(Data);
}
This will allow you to display HTML
I've implemented a few poor solutions for bringing up an AJAX loader before dynamically updating a content DIV, but none seem to be "universal", and I find each time I do it I'm reworking it. If I have a DIV with content that updates depending on what a user clicks on the page, and I want to display the loader over this content DIV, what is the best approach? I've seen some developers have the loader always on the page, and they just display it block or none, and I've seen others append it to the DIV. What about when you also have multiple areas that can update? I'm thinking something repeatable that I can call with a function, maybe passing a few parameters.
Some JavaScript libraries allow listening to opening and closing requests. Check out Prototype's request Responder http://www.prototypejs.org/api/ajax/responders.
You would do something like this:
Ajax.Responders.register({
onCreate: function() {
$('loader').show();
Ajax.activeRequestCount++;
},
onComplete: function() {
Ajax.activeRequestCount--;
if (Ajax.activeRequestCount < 1) $('loader').hide();
}
});
As for visual representation of loading, you may want to identify the different parts of your page which may require separate loading graphics and subclass the Request object, each time indicating the type of request.
E.g.
Is it a field being saved? new FieldUpdateRequest(field)
Is it the page being loaded? new Request();
Is a container being updated? new PartialRequest(div);
Then capture each subclasses type and show or hide a different loader graphic.
There is unfortunately no quick solution, hal. You could build a generic script for appending loader graphics to containers, that should save you some repetition. If you do, mind posting it here :)?
You could use a JQuery progress bar or something similar in a different library.