How to structure app with Angular JS - javascript

I am trying to learn Angular JS and use it in my web app project and am looking for some guidance as well as answers to specific angular js questions. Tech stack I am using is MySQL db, Java w/ Spring Framework, HTML/CSS/Bootstrap/JS, etc..
The purpose of the app is basically a "social media craigslist" where it will have:
1. User accounts
2. Ability to create a "newsfeed-esque" post (one "view")
3. Ability to create a sale post (separate "view")
4. A view for an "inventory"
5. A view for a "wishlist"
etc..
(note: Items 2-5 are accessed via a nav bar of sorts that sits on the left side of my page and the idea was to have the main section of the page switch the content based on what nav item you clicked.. more later..)
What I was doing was writing a bunch of Javscript code to make calls to my web services (grabbing static content to populate drop downs, sending user login info for logging in, etc..) and the < script > tags were growing and all of this was living in my index.html page and I thought it might make more sense to use something like Angular JS and structure it a bit differently and "modularize" the code so it wasn't a giant mess in index page. I was also doing some manual .hide() and .show() JS stuff so I thought that it also might make more sense to switch out the content using something like AngularJS instead of having maximum ONE .show() active at once and then having to do as many .hide()'s as I would need to, to manually switch out the content. This is sounding like a SPA (single page app) right?
I have researched AngularJS StackOverflow posts and looked at w3schools and other helpful websites but am having trouble with how to structure this and use best practices not only with code efforts but organizational as well.
1) Am I correct in thinking Angular would make the hide and show of content easier?
2) I would like to make each "feature" of my website have its own controller and have Controller1.js, Controller2.js, etc.. but do I need to have a
var app = angular.module('myApp', []); ...
line at the top of each controller or do I need something like a main controller with that in there only once and then a call to each controller from a main controller? Or is this not even how I should go about it? Thought process was again to modularize and avoid having one giant beastly file with all my JS logic in it.
3) I assume that I need to use the ng-route stuff (is this correct?) in order to do that hide and show of html content? (items 2-5 listed above) But in what file should that live? a javascript controller file? index.html? other?
4) I read you can only have one ng-view per application. Does that mean that you can only switch/change the content for ONE < div > / section of your web app, OR can you have multiple different divs being changed?
5) fyi - my current file structure is pretty much this.. is this how it should be?
-Java Resources (java code)
...
-WebContent
-img
-META-INF
-resources
-css (folder)
-js (folder with js files - controllers)
-WEB-INF
-lib (folder)
-views (folder)
-xx-servlet.xml
-web.xml
-index.html
-pom.xml
A lot of my questions are just because I am new to AngularJS and not seasoned in JS itself so am trying to better understand. Thanks for any and all help in advance.

First of all, if you want to use multiple views per app then you should use angular-ui-router module instead of angular-route module.
Now, we come to the file handling. So, for that you can make as much file as you can to define controllers, config, services and factories for the app. There are three ways of doing this.
The first one is putting var app = angular.module("MyApp",[]); in first file and defining controllers and services like app.controller('ctrl', ControllerFunction) in each of the other files below the first one. But, personally i don't prefer to use this way as you are exposing your app as a global variable here.
The second way is to create a main module in first file using angular.module('MyApp',[]) and in other files you can get it and define controllers using angular.module('MyApp').controller('ctrl', ControllerFunction). This is the safer way than the previous one.
The third way is to create a different module in each of the files and using all the modules in a single main module as dependencies. Like below
in one file
angular.module('Module1',[]).controller('ctrl1',CtrlFun1);
in another file
angular.module('Module2',[]).controller('ctrl2',CtrlFun2);
and in the main file, the main module, which is to be bootstraped
angular.module('MyApp',['Module1','Module2'])
This is the safest way to define services in different files. I personally advise this way of using multiple js files in single app. Because here you care not exposing a global variable or a single module, so anyone cannot inject some code using console easily.

Related

How do I split my web application?

We create a Single Page Application. Say this is ProjectA.
We then decided, due to good fortune, to make ProjectB.
90% of ProjectA and ProjectB are the same.
This is saying to me that we need ProjectCore ProjectA and ProjectB. The latter 2 must use the first as a dependency.
What muddies the water is that, it is not just JavaScript. The Designer said "I am going to have your problem but with CSS!". So I mean, if the ProjectCore has a ConfirmationModalView, then the CSS which styles that view should travel with it.
How do you handle this? Is this what WebPack and their ilk are for? What common solutions exist for resolving this problem?
"Copy and Paste all the Code from A into B then maintain both" is getting votes but this is lame. Although I can't say I can offer a solution.
You can look into Git and version control. BUT... You could have one main JS and CSS file for the stuff that is not changing.
You can then add smaller, separate JS files, for which have specific functions, for Project A and Project B individually (Note if you include below the "main JS", all the global functions and variables will be available for this JS file to use, kind of a bonus if need be).
You can then use #import url("base.css"); at the top of your two different, smaller CSS files to "combine the main CSS with new, specific CSS for "that" page only.
you need use MVC ...
your Model are the same.. becouse it is your object manager Server Side.
your View is diferente becouse you have a diferent User Interface.
and you can dev Controller as you needed... in javascript ajax to comunicate with sever by event user... Controller php can manajer default informacion. DB Connection, Encription... ETC.
you can upload static to a server as CSS and JS and core proyect PHP to the server side...
You can add Controller 1, 2, 3 or View 1, 2, 3 depending on the project an you have a core View and core Controller.

AngularJS module architecture

I am planning to create several modules in my company's application and I'm having trouble designing the architecture for the modules. I have done research and it seems like either you are supposed to use one module per page, or create a 'master' module that depends on all of your other modules. I don't like this approach because it means I have to load all of the javascript for every aspect of my application for every single page. That seems inherently wrong, but I also can't seem to figure out how to handle it the other way if I need to use one module in multiple places on a page. For example, I have a membership module that I have and I'm attaching to the header section of my web page. This would be intended for logging in, registration, and performing a 'forgot password' type workflow.
On another page dedicated to changing a password (from a reset link) the header is also present, but I want to include the password reset functionality in the membership module. I've read that one methodology of designing your application is by functionality/feature. I figured membership was an appropriate application of that, but now I'm not sure since I am having trouble applying the membership module more than once on any particular page.
Am I on the right track, or is there a preferred method for this? Should I have a separate module for the header and one for the rest of the page? Should I just bite the bullet and load everything? (I hope not...)
I should also note that this is an ASP.Net MVC application where we are still heavily relying on MVC for serving views and partial views. As such I wanted to use a render javascript section to dynamically load only the javascript necessary for that page to function. Is this a farce?
<header ng-app="membership">
//stuff for header membership functions
</header>
<div ng-app="membership">
//somewhere else that needs membership, outside of header
</div>
I personally like Mini SPAs (Silos) instead of full SPA. You can watch Miguel A Castro's video, and download the source at his website.
What it does is when a request comes in, it goes to ASP.Net MVC Route first. Then, Angular Route takes over the rest. It is a very slick design.
FYI: Angular 2 is right around the corner, so I went ahead and updated those to Angular 1.5 Compotent so that I can convert to Angular 2 easily later.
If you want, you can stop there. I went one step future, and use Strongly Typed Views using Matt Honeycutt's Building Strongly-typed AngularJS Apps with ASP.NET MVC 5 approach.
Then I implemented Angular Helpers like Axel Zarate's ANGULAR.NET – HELPERS FOR ASP .NET MVC 4.
On an Angular application, as it is a Single Page Application, yes, all your javascript must be loaded. It's the code of your application and it's necessary. That's done only once on first page load.
You're always on the same page, but on a different state.
One good approach is to define a master module who include all other modules. Those modules can also include other "sub modules" they need.
angular.module('App', [
'App.Membership'
// ...
// All others modules you need, including 3rd party modules
])
Then, on each module, you can define the different states associated and their controller
angular.module('App.Membership', [
// Module dependencies
])
.config(['$stateProvider', function($stateProvider) {
//State definition
$stateProvider.state('membership', {
parent: 'app',
url: '/member',
controller: 'MembershipCtrl',
template: '<ui-view/>'
});
}]);
You can also add a global controller to handle elements who are always present, like a header.
Hope this helps

Using Angular Dragula without RequireJS

I would love to implement Drag and Drop in my Angular project using the angular-dragula module (https://github.com/bevacqua/angular-dragula). However, it seems to be heavily dependent on RequireJS. I've not used Require for a while and only then for an example app or two. Is there an easy way to untangle Require from this module?
The author seems to think it is simple (https://github.com/bevacqua/angular-dragula/issues/23) and has shut down similar questions as well without a real explanation. I've looked at the code and don't see how to load the module without adding RequireJS to my project (which I don't want to do). Am I stuck with either not using this module or adding Require or is there a way to use this without Require?
OK, after help from those who commented (thanks everyone!), I was able to get this to work. There are a couple things that you need to do. First, I was bundling this module with the rest of my modules and trying to call it. That will not work because it needs to initialize with a parameter (angular). Therefore, you need to do the following:
Add a reference to angular-dragula.js (or the min version) to your index.html page below the declaration for angular but above where you create your app.
When you declare the dependencies for your app, specify angularDragula(angular) (not in quotes).
Use dragula as you normally would. If you need to access the service, the name would be angularDragula.
For example, here is my declaration of app:
var app = angular.module('app', [
'ngRoute',
angularDragula(angular)
]);
And then to get a simple list to be drag and drop capable, this is my html:
<div dragula='"bag-one"' dragula-model="vm.items">
<div ng-repeat="item in vm.items">{{ item }}</div>
</div>
Note that I do not declare angularDragula anywhere, unlike the examples. In the example the author gives, he requires angular and creates the angular variable and then he requires angular-dragula and creates the angularDragula variable. This is not needed if you are not using RequireJS as long as you load the scripts in the right order.

How can I get an environment specific URL into my AngularJS controller?

Situation
Our web project in production has a root URL like so: http://example.com. Our local dev instances (don't ask me why) default to a URL like so: http://localhost/SubDir where SubDir is a placeholder for the actual virtual subdirectory in IIS.
This is not the problem. As much as I would like to abolish that subdirectory URL thing, that is only illustrating a problem. If we were to move to a different domain or URL later on that incorporates a subdirectory URL, it would not be a problem for all of the instances in code where we use helpers to generate URLs (e.g. #Url.Action("GetUpdates"), etc).
Currently we have quite a bit of javascript that has been moved to external .js files that uses jQuery to get URL strings from hidden inputs whose values have been set to a Url helper like above. This is not too bad, it works.
The Problem
AngularJs. It is not the problem. It has however uncovered the problem. We want to remove jQuery from the project eventually. Right now, I am getting the URLs in my controller using jQuery (I am willing to break rules in an effort to get something out on time if I can be reasonably assured I will be given time to fix it later). It is now time to fix it, and I am at a loss.
Between the two environments, I get the following from #Url.Action("GetUpdates"):
On http://example.com/: => /Contest/GetUpdates
On http://localhost/SubDir: => /SubDir/Contest/GetUpdates
The Question
How can I get an environment dependent URL into my AngularJs controller without the use of the helpers in that controllers file? I originally thought it might be as simple as using the hidden inputs and setting the ng-model, but does not seem to have worked. I have also looked into using an extension, RazorJS, but hoped that there would be a better way of doing it more inline with the Angular paradigm.
Anyone have any ideas? How do you get URLs into your controllers?
If you are able to change your environment config server side you can put the variable inline in a module constant. Then you can inject into your main app.
Here's a Plunker
// inline
angular.module('Preload',[]).contstant('CONFIG', {'BASE_URL':'http://localhost/foo'});
// inject
var app = angular.module('MainApp', ['Preload']);
// Controller
app.controller('MainCtrl', function($scope, CONFIG) {
$scope.base_url = CONFIG.BASE_URL;

Exposing application scripts to certain scripts only

uhh it's hard to come with a right title for this problem excuse me.
In a backbone.js application i am building. Models, Views, Templates are all in separate javascript, html files. I want to export the Models, Views and Templates to the application bootstapper file (app.js) without polluting the global variable i.e doing window.App.Model = myModel; that. By export i mean make the code inside the files available to app.js for initialization and running
How do i go about doing this?
Are there any patterns that will solve the problem? Could you provide me a example
Description
In cases where models,views and templates are split to many disparate files the application bootstrapper file app.js should have some means to access these M,V,C components. Hence common approach is to do below inside the model.js file
window.App.Model.PersonModel = Backbone.Model.extend({});
App.js
var instance = new window.App.Model.PersonModel();
var personView = new window.App.Views.PersonView({model:instance});
Finally you see that everything derives from the Global object App which i think is not safe, improper and weak way to build application dependencies
Suggestions
Just to the above question, could someone suggest a template loading library(javascript templates regardless of engine used) that can be used to load the templates
Take a look on RequireJS, which support asynchronous module definitions/loading. You would have to rewrite your modules to and app.js to satisfy AMD api, but it would take only few strings of code.

Categories

Resources