I have a Django application with an AngularJS frontend. The application sends notification emails, which it renders using Django templates.
ITEM: {{article.title}}
DATE: {{article.date}}
SOURCE: {{article.link}}
{{article.body}}
The issue is article.link. The previous version of the application didn't use Angular, so it was simple to find the link. In urls.py we had
url(r'article/(?P<article>\d+)/$', views.ArticleView.as_view(), name='show-article')
which meant that we could reverse a URL to a particular article with
django.core.urlresolvers.reverse('show-article', kwargs={'article':article_id})
Now, on the Angular-based revamp of the site, the display URL for an article looks like /mysite/#/article/1234 and is determined by routes.js:
$routeProvider.when('/article/:articleId', { ... } )
Bottom line, I don't have a way to grab an AngularJS route from Python. I could hard-code the all the routes from routes.js into something the backend sees, but it wouldn't be very DRY. I could generate routes.js dynamically with Django, but right now none of our other JS source is touched by Django -- that doesn't seem very clean either. Maybe I should continue to support the old-style URLs (/article/1234) as a redirect to the Angular-style URLs (/#/article/1234)? That still requires logical duplication, I think.
Is there a better pattern I should be using here?
Decoupling clients and servers is often a goal so duplication should not be considered a bad thing in this case. Depending on your needs however there are solutions which provide a reverse method which behaves like in Django. There is django-js-reverse and django-angular for angular specificaly.
Related
As far as I know the hash symbol(#) is the key when implementing routing in Angular. The web server only takes care about the part of the URL which is before the hash, and Angular takes care of the rest.
I´ve read some articles that explain how to remove the hash from URL. But if I remove the hash(#) from URL: Which routing works first?
OK, it is MVC. In that case we have to edit the MVC Route in order the server to understand the URL. But we are at the beginning again. Does it make any sense to use Angular Routing and MVC together ? Is not enough with MVC Routing?
Maybe I´m missing something. I hope you can help me.
Does it make any sense to use Angular Routing and MVC together ? Is
not enough with MVC Routing?
TL;DR;
I've rarely use both. The only time I use both is when I need to authenticate the user for some routes.
Long answer
1. Authentication
As you already figured out, Angular routing is great when you want to navigate to another page without the roundtrip to the server. It's usually a SPA. But there might be a scenario when you need to authenticate the user before sending the HTML, then MVC routing will be handy. I wrote an answer about it here. Note the difference between sending HTML and sending DATA to to the client. If you have no server routes the html-pages (or templates) will be fully accessible (unless you limit access in web.config or some other way). Some times the HTML-pages can contain some sensitive information as well...
The most common scenario is if you have a public site with an admin-part. But in my experience you can handle this on client side with client-side-routing only. It's usually the data that is sensitive, not the templates.
2. Server-side logging
The other scenario is when you want to do some logging on server side. For example if you want to log every page request. This can often be done on the client as well... Look at Google Analytics. But you might want to log the request even if the browser has javascript turned off.
3. SEO
There might be some SEO-issues when using client-side-routing. But this is only when we render the html with client side templates and if we compare to completely rendered views with MVC.Net. Do not confuse me posting the link with me actually agreeing with the content...
4. WCAG
In my country all government sites need to follow WCAG. One of the rules are - no javascript. Or at least that the site should be fully accessible without javascript. Without javascript client-side-routes are simply very difficult. ;)
These are some examples when you might need both server-side and client-side routes. But to sum up, in most cases client-side is enough.
I am developing an app with an AngularJS front end and a Laravel API backend. The Laravel backend just listens for requests, process them and returns an answer. Front and back end are different independent apps... so far. I did it in such a way in order to be able to develop a mobile app later on which could consume the API. Im using also JWT to authenticate users, so Im not using Laravel's sessions at all. At this point I only require a webapp. I built a webapp which uses angular ui-router.
So far so good. The front end and the back end work well. However some of the front end views will be public and require share buttons, they also require to be indexable by Google.
I've read there are some alternatives.
Make some hack using the apache mod_rewrite in order to serve the angular app for people and a static version of it served directly by the backend. I think this would not be very difficult using Laravel.
Using Prerender.js. Which as far as Im concerned does pretty much the same job than option 1 but in a more complete manner.
However I am thinking about using a third alternative. Given that I only require the webapp now and the API is working I am thinking about using Laravel's built-in webapp functionality. I can use the controllers, directives and factories from angular and let Laravel handle the webapp routing.
An advantage of this is that I can render the meta tags using Blade (this fixes completely the SEO issues) and serve the rest of the contents using angular and the API.
Do anyone of you can see drawacks of such a solution or do you know a better way to accomplish SEO purposes using angular and Laravel?
Render Site :
You will have to render the pages from server side if you want to make it SEO friendly. But yes, what if you serve the server rendered pages to bots only. And for real users client side rendering will work.
Read about the Rendertron which will detect the user agent and accordingly serve the html.
Meta Tags :
Use Sluggable and replace id with slug in urls. You can follow https://oodavid.com/article/angularjs-meta-tags-management/
I'm deciding whether it's safe to develop my client-facing app in AngularJS using pushState.
I've read that when using pushState in an AngularJS app, we don't need to worry about Googlebot because it can now execute enough JS to produce an HTML snippet for itself. But then I wonder about Bing, Facebook and other bots and scrapers. The tutorials I've seen for making AngularJS SEO-friendly all deal with apps that use hashbangs (#!). These don't apply to me since I'm not using hashbangs.
Does anyone have insight into this problem? What are some methods for ensuring an AngularJS app that uses pushState is SEO-friendly and Social-scraper-friendly? If you use a service like Seo4Ajax or prerender.io I'd appreciate your thoughts on it.
Note: As I understand it, when developing single page apps in the last couple of years it has been necessary to send HTML snippets to SEO crawlers. This was accomplished by using hashbangs and a meta tag that let Google, Bing and Facebook know that it needed to replace the bang (!) with an _escaped_string when making a request. On the server you'd listed for requests with _escaped_string and deliver the appropriate HTML snippet using a tool to generate HTML snippets like phantomJS.
Now that we have pushState, I don't see how we indicate to javascript-less bots what part of the URL to rewrite with an _escaped_string or even if it's necessary. I'm having trouble finding any information beyond "you're site will be okay with google ;)".
Here are some other SO questions that are similar but have gone unanswered.
Angularjs vs SEO vs pushState
.htaccess for SEO bots crawling single page applications without hashbangs
Here's a solution I posted in that question and am considering for myself in case I want to send HTML snippets to bots. This would be a solution for a Symfony2 backend:
Use prerender or another service to generate static snippets of all your pages. Store them somewhere accessible by your router.
In your Symfony2 routing file, create a route that matches your SPA. I have a test SPA running at localhost.com/ng-test/, so my route would look like this:
# Adding a trailing / to this route breaks it. Not sure why.
# This is also not formatting correctly in StackOverflow. This is yaml.
NgTestReroute:
----path: /ng-test/{one}/{two}/{three}/{four}
----defaults:
--------_controller: DriverSideSiteBundle:NgTest:ngTestReroute
--------'one': null
--------'two': null
--------'three': null
--------'four': null
----methods: [GET]
In your Symfony2 controller, check user-agent to see if it's googlebot or bingbot. You should be able to do this with the code below, and then use this list to target the bots you're interested in (http://www.searchenginedictionary.com/spider-names.shtml)...
if(strstr(strtolower($_SERVER['HTTP_USER_AGENT']), "googlebot"))
{
// what to do
}
If your controller finds a match to a bot, send it the HTML snippet. Otherwise, as in the case with my AngularJS app, just send the user to the index page and Angular will correctly do the rest.
Supposedly, Bing also supports pushState. For Facebook, make sure your website takes advantage of Open Graph META tags.
I feel like both Express' and any MEAN stack tutorials gloss over this, so I decided to ask here.
See also these similar SO posts:
Why would one want to use Express instead of AngularJS?
Angular and Express routing
Using plain HTML with Angular directives/attributes as the view engine in Express, what's the best practice for rendering page partials in a single layout template with regards to routes?
How do you do this with HTML/Angular as your view engine?
In Jade, you'd do something like block content.
Do you use the Angular Router, ng-view and use directives?
If so, what's the point of Express? Just a server? Why not just use Connect?
P.S. If you're wondering about Jade or EJS, I'm just learning Express, and Angular, so I'm trying to keep language abstractions to a minimum.
I guess my confusion originates from the overlaps between Express and Angular in regards to templating and routing, but Express focuses on the server-side, and Angular, the client. For someone just learning these, it's tough to know how to implement when everything is so wide open.
I'm looking for detailed, specific implementation code examples that use best practices when it comes to separation of concerns. Seeing it and having it explained in context is how I learn best from others.
Check out angular-blocks if you want jade-like blocks:
https://github.com/wmluke/angular-blocks
It's important to understand that Angular and YOUR_SERVER is generally irrelevant. It's a matter of "where do my files go". As single-page application suggests, it is a single static route. I'm sure Connect would handle this just fine, but the server portion of your application likely has more concerns than simply serving a static page. Authentication, business logic, API routes and other concerns come into the picture at some point, so Express (and its ecosystem) makes a lot of sense.
Your single-page application will definitely have its own routes. These are unrelated to your servers routes, which will include the static route to the Angular application page, and also any routing for API calls that the Angular app will be making.
It's important to understand that you are writing two distinct and separate applications, connect via an API. The fact that your Node server is delivering the static HTML and JS is, for the most part, coincidental. The Angular application should be considered, and developed, in an isolated, decoupled way for best results.
Express and angular serve totally different purposes.
In most MEAN-like stacs situation (for example just express-angular), express acts as server PLUS API provider.
You use app.get('/') with any server side templating like jade (just to have cleaner html files...), then You use app.get('/partial/:name') to handle all partials with same template language.
then, You use app.get('/api/anyapi1'), app.get('/api/anyapi2') to provide whole api to angular - no matter what it will be - some mongo or postgres handling, or just Your static json files.
In new express4 You can also create dedicated api route with:
var api = express.Router();
api.get('/somget', function(req, res) {
res.send('some json');
});
// init api route. all api routes will begin with /api
//(like above api.get will be at /api/somget)
app.use('/api', api);
You can also deal with sessions and authorization on express side, and whole awful lot of stuff, that shouldnt or cant be done on client side.
Hope it helped.
EDIT: speaking shortly: express is backend with http server, other services and api, and angular is whole frontend which consumes what backends provides.
Having such separation You can even provide that backend api to others, or build different services on top of it.
Correct, the MEAN stack puts an emphasis on making most of your logic on the front end. Your express server will act as a mule to save, read, validate, and delete data based on the get and post request you make from the front end.
The idea is to have all your front end code in a public folder of your express app.
`app.use(express.static(__dirname + '/public'));`
Then simply make a route that renders the index file as such
`app.get('/',function(req,res){
res.render('index')
})`
With this in mind you may we wondering if there is a solution that can generate an api for you so that you just name your models and the rest is done via angularjs services. There is.. http://loopback.io/ just name your models, relationships and restrictions. It will generate an enteprise level api for you to play with.
For a complete working example on how routing is done and how to model your app check out this tutorial: http://www.ibm.com/developerworks/library/wa-nodejs-polling-app/
I have an Angularjs app running on Sinatra.
My Angular routes are working if I click on a link within the app, however if I visit the url directly I get a 404 from Sinatra.
Is there a way to pass the routing from Sinatra to Angular?
Currently all Sinatra is doing is loading the index.html
get '/' do
File.read "#{Dir.pwd}/app/index.html"
end
Thanks to #Ryan I ended up implementing a working solution.
get '/*' do
File.read "#{Dir.pwd}/app/index.html"
end
One way you could do this would be to set up a catch-all route with Sinatra to pass requests on to your angular app. I'm not very familiar with the sinatra framework, but for flask this is how you do it:
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def index(path):
return make_response(open('templates/index.html').read())
Just find the equivalent for Sinatra and you'll be good to go.
EDIT: I realized it is probably not the best idea to set up a catch-all route, especially if you are building a website (and using "$locationProvider.html5Mode(true)" vs. building a single-page webapp), for which returning proper 404's is important for search engine indexing, etc.
I would instead register a flask route for every route in your Angular app. In flask, this is how you do it.
#app.route('/')
#app.route('/about')
def index(path):
return make_response(open('templates/index.html').read())
In sinatra, I'd suppose it would be something like this:
get '/' do
get '/about' do
File.read "#{Dir.pwd}/app/index.html"
end
EDIT: It really depends what you're going for. Some sites want their entire site to be an angular app (and don't prioritize SEO, proper 404's, etc.) and others want a particular section to be reserved for their angular app. You might see "/app/OTHER_STUFF", for example. In that case, a catch all would work well.