I have a two CRUD screens in AngularJS.
1) Separate html file for View, Add and Edit. View Controller, Add Controller and Edit Controllers also Separate. This structure creating more duplicate code in html and controller side.
2) Separate html file for View, Add. View Controller, Add Controller only Separate. During edit mode I'm using a Boolean in controller to find its in edit mode or not.
I'm new to AngularJS. Anybody clearly tell me pros and cons, which way is correct in AngularJS 'Separation Of Concerns' concept.
I'm not sure you're going to the good direction.
By separation of concern, what is intended is to split the code that is responsible for managing the view, and the code responsible to make calls to your server. Imagine you want to make CRUD around a person, I would do the following :
service :
angular.module('app').factory("personService", ["$http", function($http)]){
return {
create : create,
update: update,
remove : remove,
get: get
};
function create(person){
return http.post("person/create", person);
}
// other functions
}
Then, I would only have 1 controller for everything :
angular.module("app").controller("PersonController", ["personService", function(personService)]){
var self = this;
self.isUpdate = true; // Insert logic here
self.isCreate = false; // Insert logic here
init();
self.save = function(){
var promise = self.isCreate ?
personService.create(self.person)
:personService.update(self.person);
promise.then(function(result){
// Handle return of save;
});
};
function init(){
if (!self.isCreate){
personService.get(personId).then(function(result){
self.person = result.data.person;
});
}
}
}
And then I would have the following view :
<div ng-controller="personController as person">
<label>Name: </label>
<input type="text" ng-disabled="!person.isUpdate" ng-model="person.person.name" />
<button ng-click="person.isUpdate = !person.isUpdate;">Edit</button>
<!-- Edit : the code 'person.isUpdate = !person.isUpdate;' could also be into a controller's function (like the save function) -->
<button ng-click="person.save()" ng-if="person.isUpdate">Save</save>
</div>
I also recommend you to read this : https://github.com/johnpapa/angular-styleguide
Separation of concerns means that you have a well defined structure of your application: the data model in the application is decoupled from the business and presentation logic. It is the base of the MVC pattern, which defines the view, the controller and the model.
This separation makes the code maintainable and easy to test.
Follow this guidance how to architect your Angular application.
The model should:
Include the domain data;
Implement the management of the domain data (query, edit, delete, storing mechanism, REST implementation, http fetching);
Expose an API that makes possibly the model usage in controller or other service;
The model should not:
Provide the details on how the domain data is managed (all REST implementation, http calls should be encapsulated in the model);
Contain logic that transforms the model based on user interaction (it is controller's role);
Contain logic for displaying data to the user (this is the view’s job);
A controller should:
Contain the logic required to initialize the scope;
Contain the logic/behaviors required by the view to present data from the scope;
Contain the logic/behaviors required to update the scope based on user interaction;
A controller should not:
Contain logic that manipulates the DOM (that is the job of the view);
Contain logic that manages the persistence of data (that is the job of the model);
Manipulate data outside of the scope;
A view should:
Contain the logic and markup required to present data to the user
A view should not:
Contain complex logic (this is better placed in a controller);
Contain logic that creates, stores, or manipulates the domain model.
This guidance is taken from this awesome book, which I recommend for any starting AngularJS developer.
Related to your example, in my opinion you should:
Create a controller and a template for editing and adding; Depending on model's isNew property, you can apply editing or adding action;
Create a controller and a template for viewing the model;
Optionally, if you have a collection of models, you can create a new controller and view also.
However it depends on the amount of logic behind the model. If the model is trivial, probably you can implement everything in a single controller and view. But it's rare.
Related
I have a list of employees in Employees view where I can add and a new employee and delete an existing one.
For listing the employees, I use an ng-repeat in the view and I can delete the particular employee by calling my splice method in controller with the passed Id and Index value.
and for editing, I use angular(copy) then update the edited value in DB. Everything is fine regarding to Add a new employee, edit and delete an employee.
I wrote all the codes in single view - single html and its too large in size. I used ng-show / ng-hide to perform add/edit actions.
I would like to break code to several views for add and edit the employee info and I use the same EmployeeController for all the CRUD operations in employee model.
If I break the employee.html to several views then I have to initialize the controller and ended up with losing the data. I can use $rootScope here to persist my data but it will pollute my structure as global is an evil thing.
Please suggest me a best practice to handle this situation. Thanks in advance!
Here is my code,
// To get all employee instances
$scope.getEmpList = function(){
$scope.employees = EmployeeFactory.getEmpList();
}
// Update employee details
$scope.editEmp = function(empObj){
$scope.updatedEmpObj = angular.copy(empObj);
EmployeeFactory.updateEmployee($scope.updatedEmpObj);
}
You should use a service to hold your data and inject that service into each controller where you need the data. A service is a singleton, and is instantiated only once.
See Using angular service to share data between controllers for more details.
I'm trying to get a practical grasp of MVC model implementation (not the conceptual understanding) in JavaScript.
As for the start, I thought it would be worth making an effort and try building a MVC app in plain JS. I've read dozens of articles and book chapters referring to MVC and its variations. Of course I googled lots of examples to see how it's done for real. The most understandable and with the proper meaning is in my opinion this one:
https://github.com/tastejs/todomvc/tree/master/examples/vanillajs
In the end, I was able to refactor my own app in the todomvc-vanillajs way.
However, there is one thing that still bothers me. All these apps and examples are very basic, so there is only one Model, View and Controller specified for the whole app.
What if I wanted to add more (equally complex) features to such app?
Should I add them one by one to my controller.js view.js and model.js files or whether should I stop developing spaghetti code and add new files instead, thus creating new models, controllers and views for each of the new feature individually?
It seems to me, that every feature should have its own view, controller and model, or at least, could have, depending on the subjective evaluation. But I'm not quite sure how such implementation should look at this situation in terms of code structure, namespacing etc.?
What if I want to imitate a scale by creating multiple views, models and controllers on every single functionality like e.g. handling an "add task to the list" or "delete the task" actions.
For the purpose of my dilemma, I've created my own MVC draft, which has two models, controllers and views. Whether such an approach would make sense? What happens when further developing my application, I quickly get to the point where I have dozens and more specific (coresponding) models, views and controllers.
Heres is the aforementioned fiddle.
;(function () {
'use strict';
/**
* #file ./App.js
*/
var App = {
Model : {},
Controller : {},
View : {}
};
console.log('start');
window.App = App;
})();
/* -------------Views-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildAdd.js
*/
var buildAdd = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildAdd = buildAdd;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
/**
* #file Views/buildDelete.js
*/
var buildDelete = {
// render
// event
// pass the reference to event handler in Controller
};
App.View.buildDelete = buildDelete;
})(App);
/* -------------Controllers-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.addController = addController;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteController = {
// handle the event and decide what the Model has to do
// handle the response from Model and tells the View how to update
};
App.Controller.deleteController = deleteController;
})(App);
/* -------------Models-folder----------------------*/
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var addModel = {
// send request
// get response
};
App.Model.addModel = addModel;
})(App);
/* -------------separate-file-----------------------*/
(function () {
'use strict';
var deleteModel = {
// send request
// get response
};
App.Model.deleteModel = deleteModel;
})(App);
/* -------------separate-file-----------------------*/
Thus, I found this question very similar to mine, but the provided answers are not entirely satisfactory, at least to me.
Check my implementation of so called Single Page Application framework. The whole thing is of 60 lines of code. It uses jQuery but can be implemented in VanilaJS.
Basic idea is simple - your app is just a collection of pages a.k.a. views
<section id="route1" src="content1.htm" />
<section id="route2" src="content2.htm" />
...
Sections id's define set of possible "routes"
SpAPP catches browser's navigate event and load requested view on the route.
And partial content1..N.htm files contain view markup, setup and controller functions.
Data model here is JS data received from server and stored in memory or in local storage.
As of MVC frameworks in general... You cannot bring joy to everyone and free of charge. That small SpAPP thing that can easily be understood and adjusted to particular project's needs is a way to go I think.
Looking at my experience in Ruby on Rails framework, I don't always need all three elements of MVC pattern. Sometimes you need a model for a database but it's only accessed internally, not by the client. Or sometimes you only need a generic helper class.
As a convention, the files are split, each one has its own controller, model and view, following a naming convention, maybe something like:
articles-view.html
articles-controller.js
articles-model.js
Views are split for each action in the controller:
articles-index.html
articles-show.html
articles-update.html
...
articles-controller.js
articles-model.js
Inside the controller, you will have the "actions", the functions for everything semantically related to an Article in a blog.
function ArticlesController() {
function index() { ... }
function create() { ... }
function edit() { ... }
...
function delete() { ... }
}
In models, you basically have the class / prototype itself, something that is built with the given data.
function Article() {
this.name = "";
this.author = "";
this.text = "";
this.dateCreated = "";
}
And finally, your views should have element with the same name used in the model.
If you have a basic CRUD system, for example, you can have just one controller and one model, but different views (one for listing all items, one for creating and editing, one for just one item, etc).
Taking examples from Rails and NodeJS, a way to write less code for the views is by using "partials". Common HTML structures can be saved on a file and imported into other HTML files as needed, such a form, the headers, the footer of a page and so on.
Example:
Instead of having a form on articles-create.html and another on articles-edit.html, you will have something like:
_articles-form.html <- this is your partial!
articles-create.html
articles-edit.html
"_articles-form.html" will be imported / appended into the create and edit pages.
Other common features can be consider as "Helpers". They are not a letter in "MVC", but often used. Like the Datepicker library, a simple validation function, a parser, etc. Something that can be used by everyone, not a specific feature of a class.
The project structure could be something like:
app/
app/controllers/
app/controllers/articles-controller.js
app/models/
app/models/articles-model.js
app/views/
app/views/articles/
app/views/articles/index.html
app/views/articles/create.html
app/views/articles/edit.html
app/views/articles/delete.html
app/views/articles/_form.html
Also, having a Manager functionality as you described above, will help you load all the data needed. Some function that maybe will read a json file, looking for the feature's name and parsing through the file's names, loading everything.
The manager would check if there is a model file, a controller file and a folder with N view files in it, containg the word "articles". The same would happen to "authors", "comments", "users" and so on.
I understand that you are proposing this question for study reasons and you took JS as a personal preference, so I´m not saying "don't try it" or something like that. But something to consider: the MVC pattern tackles applications that involves both client and server side. Unless your are developing on a full stack with NodeJS and MongoDB (or other similar technologies), HTML and Javascript are more on the View side of the application (or as helpers).
And if you are developing something like a library, you'll end up putting everything on a single file and minifying/uglifying it. Take JQuery as an example. Javascript developers often go with the Module pattern. They create an object, expose methods and variables that the other developer needs to know and that's it.
So, probably (but not for sure, you never know!), you won't see or work on many vanilla Javascript applications implementing MVC pattern.
I have implemented a single page application with AngularJS. The page consists of a content area in the middle and sections assembled around the center that show additional info and provide means to manipulate the center.
Each section (called Side Info) and the content area have a separate AngularJS controller assigned to them. Currently, I communicate via $rootScope.$broadcast and $scope.$on(), e.g.
app.controller('PropertiesController', function ($scope, $rootScope) {
$scope.$on('somethingHappened', function(event, data){
// react
});
});
I then call to communicate with other controllers:
$rootScope.$broadcast('somethingHappened', data);
I have quite a lot of communication happening between the Controllers. Especially if something is going on in the content area, several side info elements have to adopt. The other way around is also frequent: a user submits a form (located in a side info) and the content area and other side info elements have to adopt.
My question:
Is there a better way to handle SPA with heavy controller communication?
The code works fine but it is already getting a bit messy (e.g. it is hard to find which events are handled where etc.). Since the application is likely to grow a lot in the next weeks, I'd like to make those changes (if there are any better solutions) asap.
This is really interesting. Pub/Sub should be a right solution here.
You could add extra order to your project by using Angular services as your MVC's model, and update this model for each change. The issue here is that you should implement an observable pattern inside your service and register to them, in order for this to be live synced. So - we're back to Pub/Sub (or other Observable solution that you could think about...).
But, the project will be better organised that way.
For example - SideInfo1Service will be a service/model. Each property change will trigger an observable change which will change all listeners:
myApp.factory('SideInfo1Service', function($scope){
var _prop1;
return {
setProp1: function(value){
$scope.$broadcast('prop1Changed', value);
_prop1 = value;
},
getProp1: function(){
return _prop1;
}
}
});
You could find those really interesting blog posts about using Angular Services as your MVC's model:
http://toddmotto.com/rethinking-angular-js-controllers/
http://jonathancreamer.com/the-state-of-angularjs-controllers/
And, this post is about observable pattern in Angularjs:
https://stackoverflow.com/a/25613550/916450
Hope this could be helpful (:
You have multiple options in order to avoid broadcasts calls:
Share data between controllers using services like it was mentioned in the comments. You can see how to this at: https://thinkster.io/egghead/sharing-data-between-controllers
Create a main controller for the whole page and child controllers for each section (Content Area and Side Info). Use scope prototype inheritance. For example:
if in main controller you have:
$scope.myObject = someValue;
in child Controllers you can set:
$scope.myObject.myProperty = someOtherValue;
you can access myObject.myProperty from your Main Controller
You can use
$rootScope.$emit('some:event') ;
because it goes upwards and rootscope ist the top level
use
var myListener = $rootScope.$on('some:event', function (event, data) { });
$scope.$on('$destroy', myListener);
to catch the event
Then you have a communication on the same level the rootscope without bubbling
Here is my implemented eventbus service
http://jsfiddle.net/navqtaoj/2/
Edit: you can use a namespace like some:event to group and organize your event names better and add log outputs when the event is fired and when the event is catch so that you easy can figure out if fireing or catching the wrong eventname.
Very important question and very good answers.
I got inspired and created three plunks showing each technique:
Broadcasting: http://embed.plnkr.co/lwSNDCsw4gjLHXDhUs2R/preview
Sharing Service: http://embed.plnkr.co/GptJf2cchAYmoOb2wjRx/preview
Nested Scopes: http://embed.plnkr.co/Bct0Qwz9EziQkHemYACk/preview
Check out the plunks, hope this helps.
I am trying my hands on the new ExtJs 5.
I have created a small app as per the defined MVC pattern of ExtJs5.
Am using ViewControllers for each View.
Problem Statement: Now suppose I have two VCs (Controller1 & Controller2). Each has its own methods. I wish to call a method of Controller2 from Controller1. I want to update the View associated with the Controller2 from Controller1.
E.g. Suppose there is a separate view for Status Bar and a ViewController(StatusBarController).
This VC has a method to update the view based on whatever message it receives as input parameter.
All the other controllers in the application will call this VCs method to update the status of the application on the status bar.
In the previous versions, this.getController('StatusBarController') was used to get the handle to any controller and then call its method.
But this is not working in my case when I use a ViewController.
Can anyone guide me how to achieve this thing? And also whether it is the correct/ideal way to do such a thing or is there any better option?
Here is my code:
StatusBarView:
Ext.define('MyApp.view.statusbar.StatusBarView', {
extend : 'Ext.panel.Panel',
controller: 'StatusBarController',
region : 'south',
xtype : 'status-bar-panel',
html : 'This is a status bar'
});
StatusBarController:
Ext.define('MyApp.controller.StatusBarController', {
extend : 'Ext.app.ViewController',
alias: 'controller.StatusBarController',
updateStatusBar : function(message) {
this.getStatusBarView().update(message);
}
});
Some Other Controller in app:
Ext.define('MyApp.controller.ResourcesPanelController', {
extend : 'Ext.app.ViewController',
alias : 'controller.ResourcesController',
onItemClick : function(tree, record, item, index, e, eOpts) {
// here I am calling the other controller's method.
this.getController('StatusBarController').updateStatusBar(
record.data.text + ' has been clicked');
}
});
ViewControllers are tightly related to their views, they are even created and destroyed together with views, and they should be controlling only their own views. The idea is to separate logic from UI on the view level.
Calling methods of one ViewController from another is not a good practice and, for big applications, it is route to hell as it inevitably leads to unmaintainable spaghetti code.
The correct approach is minimize the number of ViewModels, ViewControllers and Controllers and let them work in their own areas of responsibilities.
For example: Suppose you want a grid and form in a container. Form would allow editing of the record selected in the grid. Plus some buttons. These three views (container, grid and form) together form a unit. Thus:
only one ViewController at container is needed, all views can use it
only one ViewModel at container is needed, all view can use it
if you want to let this trio to communicate with the outer world of the rest of the application, the container's view controller can fire events and can have API methods to call
Thus, if needed, you can have an MVC (global) Controller(s) that would coordinate functions of units, like our trio.
Also, data binding simplifies the logic to a great degree so controllers and listeners are not needed that much.
See Binding Grid and Form in ExtJS 5 example.
my answer is simple and short:
Ext.app.ViewController.fireEvent()
while one can add any type of custom event with the listeners config of the ViewController - the docs of the listen config state "event domains", so I'd assume, that both controller need to reside within the same domain in order to be able to interact, event-wise.
the 2nd argument of .fireEvent() might need to imitate the element which ordinary triggers the event.
well, it should also be possible to access it like that (in the secondary controller):
this.getApplication().getStatusBarController().updateStatusBar('...');
As i tried to learn some Angular in the past weeks, i have adopted a certain application architecture.
Assuming a intermediate large SPA, i create the view and apply a maincontroller:
<html ng-app="app">
<body ng-controller="appCtrl">
<!-- All of the view goes in here -->
</body>
</html>
Now i think about the stuff that my application will have to do. Assuming that this one would have to store some data and working with it, i would create a provider to build a "class".
var data = angular.module('data', []);
data.provider('$dataObject',function(){
this.$get = function($http){
function DataObject(){
var field = "testvalue";
var object = {
// ...
}
}
DataObject.prototype.processData = function(){
// do something
};
return {
Shipment: function(){
return new Shipment();
}
}
}
});
I would then create an instance of that class in my maincontroller, storing all of the necessary data from the view into that object, processing it by calling the class methods.
If the application would need another functionality, e.g a dialog to pick some stuff, i would repeat the steps above and create a class for that dialog.
Now, while i am quite comfortable to do things that way, i still wonder if someone would consider this bad practice, and if so, why is that and what could i do better?
Creating services/providers for your models/data (with APIs to expose the data), and then injecting them into controllers is the "Angular way."
When I design an angular app, I think about the models I need and create services for them. I then (or in parallel) think about the views and design those. I normally create custom directives at this point also. Lastly, each view gets a controller, whose job it is to glue the models/data from the services that the view needs. (Make controllers as thin as possible.)