SlideShare uma empresa Scribd logo
1 de 38
Baixar para ler offline
Rich Object Models &
Angular
Ben Teese, Shine Technologies
Overview
Why?
Loading Data
Adding Business Logic
Advanced Stuff
Most of the apps I build are

CRUD
...it was nice
WARNING
The remainder of this presentation
contains UX that some viewers may find
disturbing
Rich Object Models & Angular.js
Proposal
Internal
Currency
NonRecurring
Engineering

External
Currency

Customer

Shipsets

External
Cost Items

Material
Cost Items

Internal
Cost Items

Customer
Type

Cost

Cost

Department

Sales Price
Override

Currency

Currency

OMG

Recurring
Engineering

Details

Years

Line
Replaceable
Unit

Currency

Customer
Type Prices
External Cost
Items

Internal Cost
Item

Subassemblies

Standard
Sales Price

Spare Parts
Sales Price
Customer
Type

Cost

Department

Supplier

Purchase Price
Ranges

Currency

Sales Price

Currency
Currency

Currency

Purchase Price

Currency
Rich Object Models & Angular.js
Rich Object Models & Angular.js
Restangular
Getting Stuff
// GET /proposals
Restangular.all('proposals').getList().then(
function(proposals) {
$scope.proposals = proposals;
}
);
or...
// GET /proposals
$scope.proposals =
Restangular.all('proposals').getList().
$object;
Getting Nested Stuff
// GET /proposals/:id/cost_items
$scope.proposal.getList('cost_items').then(
function(costItems) {
$scope.costItems = costItems;
}
);
Rich Models
angular.module('pimpMyPlane.services', ['restangular']).
factory('ProposalSvc', function(Restangular) {
Restangular.extendModel('proposals', function(obj) {
return angular.extend(obj, {!
profit: function() {
return this.revenue().minus(this.cost());
},
revenue: function() {
return this.price().
convertTo(this.internalCurrency);
}
...
});
});
return Restangular.all('proposals');
})
A Model Mixin
angular.module('pimpMyPlane.models').
factory('Proposal', function() {
return {
profit: function() {
return this.revenue().minus(this.cost());
},
revenue: function() {
return this.price().
convertTo(this.internalCurrency);
},
...
};
}
Using the Mixin
angular.module('pimpMyPlane.services',
['restangular', 'pimpMyPlane.models']
).factory('ProposalSvc', function(Restangular, Proposal){
Restangular.extendModel('proposals', function(obj) {
return angular.extend(obj, Proposal);
});
return Restangular.all('proposals');
});
What about nested models?
angular.module('pimpMyPlane.services', ['restangular']).
factory('ProposalSvc', function(Restangular) {
Restangular.extendModel('proposals', function(obj) {
angular.extend(obj.recurringEngineering, {
...
});
angular.extend(obj.nonRecurringEngineering, {
...
});
angular.extend(obj.internalCurrency, { ... });
angular.extend(obj.externalCurrency, { ... });
return angular.extend(obj, Proposal);
});
...
})
Introduce mixInto()
angular.module('pimpMyPlane.services',
['restangular', 'pimpMyPlane.models']
).
factory('Proposals', function(Restangular, Proposal) {
Restangular.extendModel('proposals', function(obj) {
return Proposal.mixInto(obj);
});
...
});
angular.module('pimpMyPlane.models').
factory('Proposal', function(
Currency, RecurringEngineering, NonRecurringEngineering
) {
return {
mixInto: function(obj) {
RecurringEngineering.mixInto(
obj.recurringEngineering
);
NonRecurringEngineering.mixInto(
obj.nonRecurringEngineering
);
Currency.mixInto(obj.internalCurrency);
Currency.mixInto(obj.externalCurrency))
return angular.extend(obj, this);
},
profit: function() {
return this.revenue().minus(this.cost());
},
...
};
});
Proposal
Internal
Currency
NonRecurring
Engineering

External
Currency

Customer

Recurring
Engineering

Shipsets

External
Cost Items

Material
Cost Items

Internal
Cost Items

Customer
Type

Cost

Cost

Department

Sales Price
Override

Currency

Currency

Details

Years

Line
Replaceable
Unit

Currency

Customer
Type Prices
External Cost
Items

Internal Cost
Item

Subassemblies

Standard
Sales Price

Spare Parts
Sales Price
Customer
Type

Cost

Department

Supplier

Purchase Price
Ranges

Currency

Sales Price

Currency
Currency

Currency

Purchase Price

Currency
Shazam
Identity Maps
Proposal
Internal
Currency
NonRecurring
Engineering

External
Currency

Customer

Recurring
Engineering

Shipsets

External
Cost Items

Material
Cost Items

Internal
Cost Items

Customer
Type

Cost

Cost

Department

Sales Price
Override

Currency

Currency

Details

Years

Line
Replaceable
Unit

Currency

Customer
Type Prices
External Cost
Items

Internal Cost
Item

Subassemblies

Standard
Sales Price

Spare Parts
Sales Price
Customer
Type

Cost

Department

Supplier

Purchase Price
Ranges

Currency

Sales Price

Currency
Currency

Currency

Purchase Price

Currency
Identity Map
“currency”:1

EUR

“currency”:2
...

USD
...

“department”:1

Finance

“department”:2

IT

...

...
Rich Object Models & Angular.js
Mapping Nested Currencies
angular.module('pimpMyPlane.models').
factory('Money', function(Currency, identityMap) {
return {
mixInto: function(obj) {
obj.currency = identityMap(
'currency',
Currency.mixInto(obj.currency)
);
angular.extend(object, this);
},
...
});
Mapping RESTful Currencies
angular.module('pimpMyPlane.services',
['restangular', 'pimpMyPlane.models']
).factory('CurrenciesSvc', function(
Restangular, Currency, identityMap
) {
Restangular.extendModel('currencies', function(obj){
return identityMap(
'currency', Currency.mixInto(obj)
);
});
return Restangular.all('currencies');
});
Getter Functions
(Uniform Access Principle)
angular.module('pimpMyPlane.models').
factory('Proposal', function(extendWithGetters) {
return {
mixInto: function(obj) {
...
return extendWithGetters(obj, this);
},
get profit() {
return this.revenue.minus(this.cost);
},
get revenue() {
return this.price.convertTo(
this.internalCurrency
);
},
...
};
}
);
Memoization
angular.module('pimpMyPlane.models').
factory('Proposal', function(Model) {
return Model.extend({
memoize: ['revenue', 'cost'],
...
get profit() {
return this.revenue.minus(this.cost);
},
get revenue() {
return this.price.convertTo(
this.internalCurrency
);
},
...
};
}
);
Unmemoization
<div ng-controller="ProposalCtrl">
...
<input type="number"
ng-model="currency.conversionFactor"
ng-change="proposal.unmemoize()"></input>
...
<table>
<tr>
<td>Number of Aircraft</td>
<td>
<input type="number" min="1"
ng-model="proposal.numberOfAircraft"
ng-change="proposal.unmemoize()"></input>
</td>
</tr>
</table>
</div>
Computed Properties
angular.module('pimpMyPlane.models').
factory('Proposal', function(...) {
return Model.extend({
...
computedProperties: {
profit: [function() {
return this.revenue.minus(this.cost);
}, 'revenue', 'cost'],
cost: [function() {
return this.recurringEngineering.cost.plus(
this.nonRecurringEngineering.cost
);
}, 'recurringEngineering.cost',
'nonRecurringEngineering.cost']
},
});
});
...needs more work
Let’s Wrap This Up
Shrink-wrapped
Boeing 737
Rich Models can work
Identity Maps
Getters, Memoization
Computed properties
Please enjoy the remainder of your flight

@benteese

Mais conteúdo relacionado

Semelhante a Rich Object Models & Angular.js

Code is not text! How graph technologies can help us to understand our code b...
Code is not text! How graph technologies can help us to understand our code b...Code is not text! How graph technologies can help us to understand our code b...
Code is not text! How graph technologies can help us to understand our code b...Andreas Dewes
 
Lerman Vvs14 Ef Tips And Tricks
Lerman Vvs14  Ef Tips And TricksLerman Vvs14  Ef Tips And Tricks
Lerman Vvs14 Ef Tips And TricksJulie Lerman
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingRiwut Libinuko
 
Fall 09 Residential Presentation
Fall 09 Residential PresentationFall 09 Residential Presentation
Fall 09 Residential Presentationkneadae
 
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)Amazon Web Services
 
Application Frameworks an Experience Report
Application Frameworks an Experience ReportApplication Frameworks an Experience Report
Application Frameworks an Experience ReportESUG
 
C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2Hammad Rajjoub
 
C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2Hammad Rajjoub
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDDKonstantin Kudryashov
 
computerscience-170129081612.pdf
computerscience-170129081612.pdfcomputerscience-170129081612.pdf
computerscience-170129081612.pdfKiranKumari204016
 
Automatic Code Generation
Automatic Code GenerationAutomatic Code Generation
Automatic Code Generationelliando dias
 
Value engineering and Analysis
Value engineering and AnalysisValue engineering and Analysis
Value engineering and AnalysisChaitanya Chenna
 
Patterns and practices for real-world event-driven microservices by Rachel Re...
Patterns and practices for real-world event-driven microservices by Rachel Re...Patterns and practices for real-world event-driven microservices by Rachel Re...
Patterns and practices for real-world event-driven microservices by Rachel Re...Codemotion Dubai
 
Patterns and practices for real-world event-driven microservices
Patterns and practices for real-world event-driven microservicesPatterns and practices for real-world event-driven microservices
Patterns and practices for real-world event-driven microservicesRachel Reese
 
Project Cost Proposal PowerPoint Presentation Slides
Project Cost Proposal PowerPoint Presentation SlidesProject Cost Proposal PowerPoint Presentation Slides
Project Cost Proposal PowerPoint Presentation SlidesSlideTeam
 

Semelhante a Rich Object Models & Angular.js (20)

Oop cocepts
Oop coceptsOop cocepts
Oop cocepts
 
Code is not text! How graph technologies can help us to understand our code b...
Code is not text! How graph technologies can help us to understand our code b...Code is not text! How graph technologies can help us to understand our code b...
Code is not text! How graph technologies can help us to understand our code b...
 
Lerman Vvs14 Ef Tips And Tricks
Lerman Vvs14  Ef Tips And TricksLerman Vvs14  Ef Tips And Tricks
Lerman Vvs14 Ef Tips And Tricks
 
O365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side RenderingO365 Saturday - Deepdive SharePoint Client Side Rendering
O365 Saturday - Deepdive SharePoint Client Side Rendering
 
Fall 09 Residential Presentation
Fall 09 Residential PresentationFall 09 Residential Presentation
Fall 09 Residential Presentation
 
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)
AWS re:Invent 2016: Building a Solid Business Case for Cloud Migration (ENT308)
 
Application Frameworks an Experience Report
Application Frameworks an Experience ReportApplication Frameworks an Experience Report
Application Frameworks an Experience Report
 
C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2
 
C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2C:\Fakepath\Combating Software Entropy 2
C:\Fakepath\Combating Software Entropy 2
 
Moving away from legacy code with BDD
Moving away from legacy code with BDDMoving away from legacy code with BDD
Moving away from legacy code with BDD
 
ACH 216 Lecture 04a (Estimating)
ACH 216 Lecture 04a (Estimating)ACH 216 Lecture 04a (Estimating)
ACH 216 Lecture 04a (Estimating)
 
CRUD with Dojo
CRUD with DojoCRUD with Dojo
CRUD with Dojo
 
computerscience-170129081612.pdf
computerscience-170129081612.pdfcomputerscience-170129081612.pdf
computerscience-170129081612.pdf
 
Automatic Code Generation
Automatic Code GenerationAutomatic Code Generation
Automatic Code Generation
 
Value engineering and Analysis
Value engineering and AnalysisValue engineering and Analysis
Value engineering and Analysis
 
AngularJs Crash Course
AngularJs Crash CourseAngularJs Crash Course
AngularJs Crash Course
 
Patterns and practices for real-world event-driven microservices by Rachel Re...
Patterns and practices for real-world event-driven microservices by Rachel Re...Patterns and practices for real-world event-driven microservices by Rachel Re...
Patterns and practices for real-world event-driven microservices by Rachel Re...
 
Patterns and practices for real-world event-driven microservices
Patterns and practices for real-world event-driven microservicesPatterns and practices for real-world event-driven microservices
Patterns and practices for real-world event-driven microservices
 
Project Cost Proposal PowerPoint Presentation Slides
Project Cost Proposal PowerPoint Presentation SlidesProject Cost Proposal PowerPoint Presentation Slides
Project Cost Proposal PowerPoint Presentation Slides
 
mean stack
mean stackmean stack
mean stack
 

Último

UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1DianaGray10
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaborationbruanjhuli
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDELiveplex
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfinfogdgmi
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesDavid Newbury
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarPrecisely
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxUdaiappa Ramachandran
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdfPedro Manuel
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6DianaGray10
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPathCommunity
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfDianaGray10
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxMatsuo Lab
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsSafe Software
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopBachir Benyammi
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 

Último (20)

UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1Secure your environment with UiPath and CyberArk technologies - Session 1
Secure your environment with UiPath and CyberArk technologies - Session 1
 
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online CollaborationCOMPUTER 10: Lesson 7 - File Storage and Online Collaboration
COMPUTER 10: Lesson 7 - File Storage and Online Collaboration
 
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDEADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
ADOPTING WEB 3 FOR YOUR BUSINESS: A STEP-BY-STEP GUIDE
 
Videogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdfVideogame localization & technology_ how to enhance the power of translation.pdf
Videogame localization & technology_ how to enhance the power of translation.pdf
 
Linked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond OntologiesLinked Data in Production: Moving Beyond Ontologies
Linked Data in Production: Moving Beyond Ontologies
 
AI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity WebinarAI You Can Trust - Ensuring Success with Data Integrity Webinar
AI You Can Trust - Ensuring Success with Data Integrity Webinar
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
Building AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptxBuilding AI-Driven Apps Using Semantic Kernel.pptx
Building AI-Driven Apps Using Semantic Kernel.pptx
 
Nanopower In Semiconductor Industry.pdf
Nanopower  In Semiconductor Industry.pdfNanopower  In Semiconductor Industry.pdf
Nanopower In Semiconductor Industry.pdf
 
UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6UiPath Studio Web workshop series - Day 6
UiPath Studio Web workshop series - Day 6
 
UiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation DevelopersUiPath Community: AI for UiPath Automation Developers
UiPath Community: AI for UiPath Automation Developers
 
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdfUiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
UiPath Solutions Management Preview - Northern CA Chapter - March 22.pdf
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Introduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptxIntroduction to Matsuo Laboratory (ENG).pptx
Introduction to Matsuo Laboratory (ENG).pptx
 
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration WorkflowsIgniting Next Level Productivity with AI-Infused Data Integration Workflows
Igniting Next Level Productivity with AI-Infused Data Integration Workflows
 
NIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 WorkshopNIST Cybersecurity Framework (CSF) 2.0 Workshop
NIST Cybersecurity Framework (CSF) 2.0 Workshop
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
20150722 - AGV
20150722 - AGV20150722 - AGV
20150722 - AGV
 

Rich Object Models & Angular.js

Notas do Editor

  1. UX is important Journeyman developer Rails I Like Angular
  2. Journeyman developer Rails I Like Angular
  3. Alternatives Nested