Designing a multi-page angular application with a focus on architectural principles

We are faced with the task of developing a multi-page application using Angular. The pages we are working on have distinct layouts and functionalities, like the ones shown in these images:

https://i.sstatic.net/NASiQ.png https://i.sstatic.net/yLS8s.png

Our approach involves assigning specific Angular controllers to each section of the page, with templates being added through the ng-include directive. For example, page 1 (route ==> '/') will consist of four different sections, each controlled by a separate controller.

While this structure works well for a single-page layout, we are unsure how to define routes within this context.

1) One option is to use nested controllers, where all other controllers are under a main page1Controller for page 1. Is this a good design choice?

or

2) Another option is to have one controller per page, simplifying routing and defining directives for each section of the page. What would be the best approach in this case?

Answer №1

In my opinion, I would suggest utilizing multiple named views for better organization. Each named view can be associated with its own controller:

$stateProvider
  .state('home', {
    url: '/',
    views: {
      '': {
        templateUrl: 'templates/app.tpl.html',
      },
      'section1': {
        controller: 'Section1Controller as vm',
        templateUrl: 'templates/section1.tpl.html'
      },
      'section2': {
        controller: 'Section2Controller as vm',
        templateUrl: 'templates/section2.tpl.html'
      },
      'section3': {
        controller: 'Section3Controller as vm',
        templateUrl: 'templates/section3.tpl.html'
      },
      'section4': {
        controller: 'Section4Controller as vm',
        templateUrl: 'templates/section4.tpl.html'
      }
    }
  })
  .state('page2', {
    url: '/page2',
    views: {
      '': {
        templateUrl: 'templates/page2.tpl.html',
      },
      'section1': {
        controller: 'Section1Controller as vm',
        templateUrl: 'templates/section1.tpl.html'
      },
      'section2': {
        controller: 'Section2Controller as vm',
        templateUrl: 'templates/section2.tpl.html'
      },
      'section3': {
        controller: 'Section3Controller as vm',
        templateUrl: 'templates/section3.tpl.html'
      }
    }
  })

Then, when designing the layout, the views should be structured as follows:

<div ui-view="section1"></div>
<div ui-view="section2"></div>
<div ui-view="section3"></div>
<div ui-view="section4"></div>

Answer №2

To enhance code reusability and prepare for migration to Angular 2, I recommend utilizing directives in order to support multiple controllers and reuse code across page1 and page2.

Your page structure will resemble the following:

<section1></section1>
<section2></section2>
<section3></section3>
<section4></section4>

Each section will require its own directive implementation:

module.directive('section1', function() {
  return {
    scope: {},
    bindToController: {
    },
    controller: function() { },
    controllerAs: 'vm',
    template: `
      <div>This is section1
      </div>
    `
  }
});

If you want more details on this approach, refer to this article about approximating modules in Angular 1.x.

For those interested in TypeScript, check out this tutorial that demonstrates using directives for shared sections between pages. The tutorial also provides a GitHub repository for reference. In the tutorial, page1 layout includes:

h1 page1
page1-section1
page1-section2

The second page mirrors the same sections:

h1 page2
page2-section2
page2-section1

To achieve this, both pages leverage similar controllers by creating section tags with shared directives (DigiSection1.Section1Directive):

angular
.module('digiangularjs.page1', [])
.controller('agendaController', Page1Controller)
.directive("page1Section1", [() => new DigiSection1.Section1Directive()])
.directive("page1Section2", [() => new DigiSection2.Section2Directive()])
;

Similarly, for the second page, identical directives are used:

angular
.module('digiangularjs.page2', [])
.controller('page2Controller', Page2Controller)
.directive("page2Section1", [() => new DigiSection1.Section1Directive()])
.directive("page2Section2", [() => new DigiSection2.Section2Directive()])
;

Answer №3

Expanding on Mike's response, I suggest defining your route-specific templates as individual components serving as top-level layout containers.

.state('page1', {
  url: '/page1',
  template: '<page1></page1>'
})
.state('page2', {
  url: '/page2',
  template: '<page2></page2> 
});

In your <page> components (responsible for laying out nested directives/components), you can structure it as follows:

.component('page1', {
  template: [
    '<section1></section1>',
    '<section2></section2>',
    '<section3></section3>'
  ].join('')
});

Considering you mentioned a "multi-page application," indicating a lack of router usage, the backend will need to handle dynamic layout generation, presenting a distinct challenge.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Launching a fresh tab or window using POST [PHP]

This is the scenario: In my project, I have two essential files - reportCaller.php and report.php. The user's interaction starts from reportCaller.php where they will click a button with an "onclick" method to trigger a function that deals with ajax/p ...

Combining Multiple Properties in a Single-File Component with Vue.js 2

Currently, my project involves Laravel 5.5 & Vue.js 2.x. After extensive research and seeking answers, I began working with components. However, I am encountering a warning message upon page rendering: [Vue warn]: Property or method "trimestral" is not def ...

What is the best way to convert a JSON string from a specific array into an array object?

JSON object: { "data": { "myStatus": "[1 2 21 0 50 0 0 0],[2 1 3 1 50 0 0 0]" }, "success": true } Upon converting to the JSON object, it appears that the myStatus is being treated as a string. The goal is to parse it as an Array inst ...

Are only PHP conventions followed when elements with name attributes are sent to the server?

There is a common belief that only elements with a name attribute are sent to the server during page change, with just the element name and its value attribute value moving between client and server. Is this functionality specific to PHP, or does it also e ...

Tips for displaying the number of selected values in a select box label (e.g. Choose an Option)

I am currently using the jQuery multiselect API in my application to allow users to select multiple values. However, I am facing an issue where I need to fetch all the selected values when a button next to the multiselect box is clicked. Unfortunately, I h ...

Using querySelector to Target Elements by their InnerHTML Content

Is it possible to target an element by its innerHTML directly without the use of loops? Is there a way to achieve this with something like document.querySelector('div[innerHTML="Sometext"]') or document.querySelector('div[textcontent="Som ...

Failure encountered when attempting to load JSON data into datalist

I've been trying to incorporate inputs into a datalist in two different ways. However, I've encountered an issue with the first method not working properly. --> Check it out on bootlply var dataList = document.getElementById('json-datal ...

How can a modal component be displayed in Nuxt3/Vue3 when it is triggered from the header component?

Currently, I am facing a challenge in calling the modal based on my header component while using nuxt3/vue3. I attempted to place the modal inside the header component and utilize the Teleport function to teleport the modal into the body based on the value ...

Discover the power of the "Load More" feature with Ajax Button on

After browsing through the previous questions and experimenting with various techniques, I've come close to a solution but still can't get it to work. The closest example I found is on Stack Overflow: How to implement pagination on a custom WP_Qu ...

Refreshing Information Iteratively

I am currently working on updating the rate field in the currency table using my nodejs controller. While everything runs smoothly in S3T / RoboMongo, I'm facing an issue where the update operation doesn't seem to execute inside the nodejs contr ...

Uploading information to a server using Angular.js

I am currently working on developing an application with the following code snippet: function attendeeCtrl($scope, $http) { $scope.submit = function () { console.log($scope.noattendees); $http({ method: 'POST', ...

How can I call the telerik radgrid.databind() function using a JavaScript function?

Currently, I am coding in ASP .NET and have an ASPX page featuring a Telerik RadGrid. I am curious to know if it is feasible to call the RadGrid.DataBind() method from within a JavaScript function? ...

Find the word you're looking for and highlight it with color

Attempting to locate a specific word within an iframe and highlighting it using angularjs and jquery. Utilized guidance from @andrew on stackoverflow for the jquery code, but facing an issue where the controller does not enter the if condition. Full code ...

Choose a div using jQuery and activate a hidden div

Seeking assistance in creating an interactive infobox that appears when hovering over a related image. Currently, the infobox pops out and flashes, but there is a problem where it shifts away from the image during the hover. I attempted to only display th ...

The Vuex store variable is being accessed prior to being populated with information retrieved from the API

I am currently attempting to retrieve data from an API using Vuex. Below is the action function in the Vuex store: async getEpisodeFromApi({ commit }, id) { const data = { id }; return await axios.get(Api.getUrl(data)).then((res ...

What is the best way to trigger a re-render in a child component in React using forceUpdate

Is there a way to force reload a child component in React, similar to using this.forceUpdate() for a parent component? For example, consider the following scenario: buttonClick = () => { // This updates the parent (this) component this.forceUpda ...

Load a Partial view once the page has finished loading

I have implemented a feature where a dropdown in my view triggers the loading of a partial view containing an input form below it. This functionality is working as expected. However, when the page is loaded with a pre-selected value in the dropdown, I wan ...

MongoSearch: A Geo-Targeted Search Engine tailored to your needs

For my new app project, I am using MongoDB, Express, JS, and Node to create a platform similar to Yelp. After some research, I discovered how to search for multiple fields within a campus schema (including campuses, restaurants, barbershops, and names). No ...

Learn how to dynamically disable unchecked checkboxes and apply specific CSS classes to checked checkboxes in Angular 12 with TypeScript

Currently, I am working on a project where I have successfully stored checkboxes dynamically using a JSON array of objects. However, I am facing an issue that requires your expertise. My goal is to allow the selection of only 5 checkboxes. Once this limit ...

Preserving the HTML format of a string stored in MongoDB: Best practices

Currently, I am utilizing AngularJS for my frontend and mongodb for backend database management. For post editing, I rely on textAngular. When creating a new post, such as a service agreement, textAngular automatically adds formatting using HTML tags. &l ...