Avatar of YZlat
YZlat
Flag for United States of America asked on

Angular application that gathers data from multiple screens

I am working on a app that switches between different screens. Each screen collect data from the user by means of user selecting a button and clicking on it or selecting a radio button. There will be at least 5-6 screens. i need ideas on how and where to store the data collected and what's the best way to move between different screens: switch what is displayed inside a div on the page or go to an entirely different page. The data on each screen is coming from the different database tables.

So far I have one screen done - it pulls data from the database(via Web API call) and based on the data pulled, displays a different image in the hyperlink.

What I want to do is capture which hyperlink is clicked by the user and store that value somewhere(a location that will persist until all data is collected and stored in the database) and then move on to the next screen. I am sort of stuck here and need some help and ideas.

here is what i got so far:

UI for screen 1:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Types</title>
    <script src="../../Scripts/angular.js"></script>
    <script src="TypesCtrl.js"></script>
</head>
<body ng-app="myApp">
    <div ng-controller="myController">
        <h3>Select a type</h3>
        <br />
        <table>
            <tr>
               
                <td ng-repeat="Type in Types">
                    
                    <a href="#"><img src="Images/type1.png" ng-show="Type.TypeId=='1'" /></a>
                    <a href="#"><img src="Images/type2.png" ng-show="Type.TypeId=='2'" /></a>
                    <a href="#"><img src="Images/type3.png" ng-show="Type.TypeId=='3'" /></a>
                    <a href="#"><img src="Images/type4.png" ng-show="Type.TypeId=='4'" /></a>
		</td>

              
		</tr>
        </table>
    </div>
</body>
</html>

Open in new window


and here is my angular controller:

(function () {
    angular.module("myApp", []).controller("myController", TypeCtrlFunction);
   
    TypeCtrlFunction.$inject = ["$scope", "$http"];
    function TypeCtrlFunction($scope, $http) {
        $http.get('http://localhost:49358/api/myAPI/GetTypes').
        then(function (result) {
            $scope.DeviceTypes = result.data;
        });

    };
})();

Open in new window


I'd appreciate some help to get me moving forward
AngularASP.NET

Avatar of undefined
Last Comment
YZlat

8/22/2022 - Mon
Gregg

One design consideration that comes to my mind is the need to share your data between controllers. See:

Passing Data between controllers:
https://thinkster.io/a-better-way-to-learn-angularjs/services
https://egghead.io/lessons/angularjs-sharing-data-between-controllers

Making UI aware of changes in data that are shared between controllers:

http://brandonclapp.com/using-angularjs-services-to-broadcast-messages-between-controllers/

These links should help you understand how to address your comment:
i need ideas on how and where to store the data collected and what's the best way to move between different screens

Also, in your code you can eliminate the repeating <img ng-show=""> tags with the following:
<td ng-repeat="Type in Types">
    <a href="#"><img ng-href="Images/type{{Type.TypeId}}.png" /></a>
</td>

Open in new window

YZlat

ASKER
Thanks Gregg, I will take a look at those links.
As far as eliminating repeating image tags, I can't use that because in reality filenames are very different, not just type1.png, type2.png
BigRat

The keyword here is "data". The data is to be collected and probably sent to the server in one call. Therefore designing the data is priority number one.

I'd put all the data into one big JSON object so that I can call it in one HTTP call and do the store just as easily.

I would not use multiple controllers - that's just too complex. Each screen would be a DIV whose display is dependant on a "pageNo" property in the JSON data :-

$scope.data = {
   pageNo : 1,
   screeen1: (),
   screeen2: (),
   screeen3: (),
   screeen4: (),
   screeen5: (),
}

Open in new window


Each <div> has an ng-show attribute which tests $scope.data.pageNo against its own number :-

   <div ng-show="data.pageNo=2>...........</div>

The fields for the elements in the view and then data.screen2.xyz.

If you want next and previous buttons on the "pages" these should be active according to data.pageNo being in range and should, on click, update pageNo accordingly. Export a couple of functions from the controller to do this.

This is a typical Survey or Quizz application of which there are several ways of doing it :-
http://odhyan.com/blog/2014/12/building-a-simple-quiz-app-using-angularjs/
https://github.com/cdeng/angularFire-survey
http://www.codeproject.com/Articles/860024/Quiz-Application-in-AngularJs
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
YZlat

ASKER
@BigRat, could you please explain? I am new to Angular. I started usinf routing and views to switch between different page - I created partial pages: screen1.html, screen2.html, and screen3.html with just some controls that would go into the main div on the index.html page. I have the routing as follows:

app.config(function ($routeProvider) {
    $routeProvider

        // route for the home page
        .when('/', {
            templateUrl: 'loginScreen.html',
            controller: 'mainController'
        })

         // route for the about page
            .when('/screen1', {
                templateUrl: 'screen1.html',
                controller: 'mainController'
            })

            // route for the contact page
            .when('/screen2', {
                templateUrl: 'screen2.html',
                controller: 'mainController'
            })

            // route for the login page
            .when('/screen3', {
                templateUrl: 'screen3.html',
                controller: 'mainController'
            });

});

Open in new window


and planning, per your advice, to use one controller to handle all the code. Now on my loginScreen.html page all i have is a form with a textbox and a button. I need help handling the onclick event on that page - to grab the value in the text box, store it somewhere and move on to screen1.html. Can you help me with that?
BigRat

I don't quite see why one needs routing for something so simple.

If you insist on login, then the first page displayed is the login page. This collects username and password and on validation you go to page 1. So the contruction at the beginning of the controller is

$scope.username ='';
$scope.password = '';
$scope.pageNo = 0;

Open in new window


The View for the login is in a <div> which has an ng-show="$scope.pageNo===0"
Just remember to attach the username and password <INPUT>s to the scope with ng-model.
And to have a simple button for submit.

Now while pageNo remains zero all the other divs with the question pages will remain hidden until the login suceeds.

Next we export a function to do the login
$scope.loginUser= function () {
   // set up an http request for a login, passing $scope.username and $scope.password to the server.
}

Open in new window


Importantly if the login suceeds, you set $scope.pageNo to 1. This will hide the login page and display the first question page.

When you come to post the answered questions back to the server you can use $scope.username and $scope.password to perform the request (authenticate and post the data in one call).

You should mock all this upp, before doing HTTPs to the server. Just write a login routine like this -

$scope.loginUser= function () {
   if(($scope.username==='bigrat')&&($scope.password==='cheese')) {
      $scope.pageNo = 1;
   }
}

Open in new window


In fact if do a mockup you can mock up the POST at the end and get all the client side code working before calling the server. This will make testing extremely easy!
YZlat

ASKER
This collects username and password and on validation you go to page 1

Open in new window


How can I accomplish that? Is it done within the controller? Could you please help me with some sample code?
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
BigRat

There is no code, AngularJS has two way binding,

<label for="usaename">Password</label>
<input type="text" name="username"ng-model="username" />
<label for="password">Password</label>
<input type="password" name="password" ng-model="password" />
<button ng-click="logInUser()">Login</button>

Open in new window


You can make this very fancy later, by adding in a span element to contain an authentication error message, and such. But for the moment keep it simple.
YZlat

ASKER
Actually no password is neeeded, I just need a username and a button:

<form method="get" id="frmLogin" action="">
    <input ng-model="username" type="text" id="txtUsername" />
    <br />
    <input type="submit" value="Login" id="btnLogin" ng-click="LoginUser()"/>
    <br />
    <span id="lblMsg"></span>
</form>

Open in new window


Now the code for LoginUser() would be in my controller?

var app = angular.module('MyApp', []);

app.controller('mainController', function ($scope) {
    LoginUser()=function(){
         //code here to go to another page?
           validateUser = function () {
                       
                if (data.isValidUser) {    
                    $window.location.href = '/screen1.html';
                }
                else
                    alert('Login incorrect');
            
        }

    }
});

Open in new window

BigRat

You must export the function like this :-

app.constant("maxPages",10);

app.controller('mainController', ['$scope','maxPages',function ($scope,maxPages) {

$scope.username ='';
$scope.password = '';
$scope.pageNo = 0;

$scope.LoginUser=function() {
   if(($scope.username==='bigrat')&&($scope.password==='cheese')) {
      $scope.pageNo = 1;
   }
}

// can display a page?
$scope.canDisplayPage = function(page) {
   return page===$scope.pageNo;
}

// next button handler
$scope.nextPage = function() {
   if($scope.pageNo<maxPages) {
      $scope.pageNo = $scope.pageNo+1;
   }
}

}]);

Open in new window


In your view you don't neeed any id numbers, you don't need any forms :-

<!-- Page 0 - the login page -->
<div ng-show="canDisplayPage(0)">
    <input ng-model="username" type="text"/>
    <br />
    <input type="submit" value="Login" ng-click="LoginUser()"/>
    <br />
    <span></span>
</div>

<!-- Page 1 first set of questions -->
<div ng-show="canDisplayPage(1)">
.......................
<button ng-click="nextPage()">next page</button>
</div>

<!-- and so on and so forth -->

Open in new window


You will replace the bigrat login with a proper one once the Angular code is finished. You don't need any routing and under no circumstances do you do things like $window.location.href.

Note how to define a constant, and also note how I injected the dependancies into the controller. If you continue to develop this app - which is a single page app which is ideal for mobile devices as well as browsers, you can minify the resultant code for better performance and easy distribution.
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
YZlat

ASKER
@BigRat, I tied that but now when I click the button and the second div becomes visible, the login div remains visible too

Also in the second div I will be displaying some data returned from web API:

<div ng-show="canDisplayPage(1)">
        <table>
            <tr>
               
                <td ng-repeat="Type in Types">

                    <a href="#"><img src="Images/abc.gif" ng-show="Type.TypeId=='1'" /></a>
                    <a href="#"><img src="Images/def.png" ng-show="Type.TypeId=='2'" /></a>
                    <a href="#"><img src="Images/ghi.png" ng-show="Type.TypeId=='3'" /></a>
                    <a href="#"><img src="Images/jkl.ico" ng-show="Type.TypeId=='4'" /></a>
                </td>


            </tr>
        </table>
        <button ng-click="nextPage()">next page</button>
    </div>

Open in new window


I also added more code to the controller and now it stopped working:

(function () {
    var app= angular.module("myApp", []);
    
    app.constant("maxPages", 10);


app.controller('mainController', ['$scope', '$http', 'maxPages', function ($scope, $http, maxPages) {

    $scope.username = '';
    $scope.pageNo = 0;

    $scope.LoginUser = function ($scope, $http) {
        alert($scope.username)
        if ($scope.username === '222222') {
            $scope.pageNo = 1;

            //get types
            $http.get('http://localhost:49358/api/myApp/GetTypes').
            then(function (result) {
                $scope.Types = result.data;
            });
        }
    }

    // can display a page?
    $scope.canDisplayPage = function (page) {
        return page === $scope.pageNo;
    }

    // next button handler
    $scope.nextPage = function () {
        if ($scope.pageNo < maxPages) {
            $scope.pageNo = $scope.pageNo + 1;
        }
    }

}]);

})();

Open in new window


P.S. Could you please take a look at my other question?

https://www.experts-exchange.com/questions/28922870/Web-API-stopped-working-ERR-CONNECTION-REFUSED.html
ASKER CERTIFIED SOLUTION
BigRat

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
YZlat

ASKER
Thank you!