AngularJS Step wizard, disable progress based on values - angularjs

I am using ui.router to create my views and I have set up this set of states:
.config(['$stateProvider', function ($stateProvider) {
// Set up our state(s)
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/index.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller'
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html',
data: {
pageTitle: 'Create your team'
}
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html',
data: {
pageTitle: 'Choose your garments'
}
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html',
data: {
pageTitle: 'Choose your design'
}
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html',
data: {
pageTitle: 'Refine your design'
}
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html',
data: {
pageTitle: 'Order your kit'
}
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
pageTitle: 'Save your kit',
requireLogin: true
}
});
}])
The index template looks like this:
<div class="container designer">
<div class="row designer-header">
<div class="col-md-6" ng-include="'/app/designer/tpls/header.tpl.html'">
</div>
<div class="col-md-6" ng-include="'/app/designer/tpls/navigation.tpl.html'">
</div>
</div>
<div class="row">
<div class="col-md-12" ng-include="'/app/designer/tpls/total.tpl.html'" ng-hide="controller.garments.loading">
</div>
</div>
<div class="row designer-body">
<ui-view></ui-view>
</div>
</div>
The navigation include looks like this:
<nav class="navbar navbar-designer">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse" id="designer-menu">
<ul class="nav navbar-nav navbar-right">
<li ui-sref-active="active"><a ui-sref=".team">Your team</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".kit">Kit</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".design">Design</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".refine">Refine</a></li>
<li><a>|</a></li>
<li ui-sref-active="active"><a ui-sref=".order">Order</a></li>
</ul>
</div>
</nav>
So, the idea is that I want to build this in steps; i.e. When the page is first loaded I would like the user to only be able to advance to the next step (.kit) when they have filled in the first page, which looks like this:
<div class="col-md-12">
<div class="alert alert-warning alert-dismissable" ng-show="controller.colours.data && controller.colours.data.length === 0">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
You must have at least one colour in the database before you can create a team / kit.
</div>
<alert-error error="controller.colours.error"></alert-error>
<form name="teamForm" novalidate ng-show="!controller.colours.loading && !controller.colours.error">
<div class="form-group">
<label class="sr-only" for="teamName">Team name</label>
<div class="input-group">
<div class="input-group-addon">1</div>
<input type="text" class="form-control" id="teamName" placeholder="Enter your team name" ng-model="controller.model.team.data.name" ng-change="controller.saveSession()" required>
</div>
</div>
<div class="form-group">
<label class="sr-only" for="colours">Colours</label>
<div class="picker colour-picker">
<div class="input-group">
<div class="input-group-addon">2</div>
<input type="text" class="form-control" id="colours" placeholder="Choose your colours" disabled>
</div>
<ul class="picker-dropdown list-inline form-control">
<li ng-repeat="colour in controller.colours.data" ng-class="{ 'active': controller.matchColour(colour) }">
<a href style="background-color: #{{ colour.hex }};" ng-click="controller.setColour(colour)"></a>
</li>
</ul>
</div>
</div>
</form>
<p><a class="btn btn-primary pull-right" ui-sref="designer.kit">Choose teamwear</a></p>
</div>
All the other "tabs" should be disabled. And then similarly, when I advance to the kit view I would like the user only to be able to advance when they have made a selection, this is the kit page:
<div class="col-md-12">
<div class="alert alert-warning alert-dismissable" ng-show="controller.garments.data && controller.garments.data.length === 0">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
It appears that your sport does not have any garments associated with it.
</div>
<alert-error error="controller.garments.error"></alert-error>
<form ng-show="!controller.garments.loading && !controller.garments.error">
<div class="form-group">
<label class="sr-only" for="clubName">Club name</label>
<div class="input-group">
<div class="input-group-addon">1</div>
<input type="text" class="form-control" id="clubName" placeholder="Choose your teamwear">
</div>
</div>
<div class="picker garment-picker">
<ul class="picker-dropdown list-inline">
<li ng-repeat="garment in controller.garments.data" ng-class="{ 'active': controller.matchGarment(garment) }"><a href ng-click="controller.setGarment(garment)">{{ garment.title }}</a></li>
</ul>
</div>
</form>
<p><a class="btn btn-primary pull-right" ui-sref="designer.design">Design teamwear</a></p>
</div>
Does anyone know how I could do this?
I can provide more information if needed.

I have answered this myself with the aid of resolve.
Here are my states now:
// Set up our state(s)
$stateProvider.state('designer', {
url: '/:sport/designer',
abstract: true,
templateUrl: '/app/designer/index.tpl.html',
controller: 'DesignerController',
controllerAs: 'controller',
resolve: {
model: ['DesignerService', function (service) {
console.log('hi');
// return our model
return service.get();
}]
}
}).state('designer.team', {
url: '',
templateUrl: '/app/designer/team.tpl.html',
data: {
pageTitle: 'Create your team'
}
}).state('designer.kit', {
url: '/kit',
templateUrl: '/app/designer/kit.tpl.html',
data: {
pageTitle: 'Choose your garments'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected our colours and our team name
if (model.team.data.colours.length > 0 && model.team.data.name) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.design', {
url: '/design',
templateUrl: '/app/designer/design.tpl.html',
data: {
pageTitle: 'Choose your design'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected any garments
if (model.kit.data.garments.length > 0) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.refine', {
url: '/refine',
templateUrl: '/app/designer/refine.tpl.html',
data: {
pageTitle: 'Refine your design'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// If we have selected our design
if (model.kit.data.design) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.order', {
url: '/order',
templateUrl: '/app/designer/order.tpl.html',
data: {
pageTitle: 'Order your kit'
},
resolve: {
model: ['$q', 'DesignerService', function ($q, service) {
// Defer our promise
var deferred = $q.defer();
// Get our model
var model = service.get();
// TODO: check for the applied colours
if (model.kit.data.templates.length > 50) {
// resolve our promise
deferred.resolve(model);
} else {
// Otherwise reject our promise
deferred.reject();
}
// Return our promise
return deferred.promise;
}]
}
}).state('designer.save', {
url: '/save',
templateUrl: '/app/designer/save.tpl.html',
data: {
pageTitle: 'Save your kit',
requireLogin: true
}
});
I admit the resolves are rather large, but I will find a way to make them smaller.
On a side note, because I am using resolve I can inject it into my controller without having to call the service again, i.e.:
.controller('DesignerController', ['$stateParams', 'model', function ($stateParams, model) {
var self = this,
slug = $stateParams.sport;
// Kit model
self.model = model;
}])
note: that the model is inject after all other dependencies. That makes a difference.

Related

Angularjs - How to prevent user from going to inner pages without logging in and how to store session upon successfull login

I am using angularjs and angularjs ui-route. I am building a login page and I want to prevent any user to go to inner pages without logging in. I have found a similar question but it lacks information. Also I want to store session upon successful login.
Here is my homeroute.js
'use strict';
var application = angular.module('App', ['ui.router']);
application.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
// For unmatched routes
$urlRouterProvider.otherwise('/');
// Application routes
$stateProvider
.state('login', {
url: '/login',
templateUrl: './views/login.html',
controller: 'logincontroller'
})
.state('/', {
url: '/',
templateUrl: './views/home.html'
})
.state('customerHome', {
url: '/customerHome',
templateUrl: './views/customerHomepage.html'
})
.state('signup', {
url: '/signup',
templateUrl: './views/register.html',
controller: 'registercontroller'
});
}
]);
application.run(function($rootScope, $location) {
var customerHome = ['/customerHome'];
$rootScope.$on('$routeLogin', function() {
if(customerHome.indexOf($location.path()) != -1 && sessionStorage.getItem('userLogin')) {
$location.path('/login');
}
});
});
application.controller('registercontroller', ['$scope', '$http', function($scope, $http) {
$scope.formData = {};
$scope.userform = "";
$scope.register = function() {
$http({
method: 'POST',
url: './services/loginsubmit.php',
data: $scope.formData
}).then(function(response) {
console.log(response);
if(response.data.empty == true) {
$scope.userform = "Please fill the form.";
} else if(response.data.emailError == true) {
$scope.userform = "Invalid Email.";
} else if(response.data.validation == true) {
$scope.userform = "Username already exists.";
} else if(response.data.validateUsername == true) {
$scope.userform = "Username must be more than 5 characters.";
} else if(response.data.validatePassword == true) {
$scope.userform = "Password must be more than 5 characters.";
} else if(response.data.registerSuccess == false) {
$scope.userform = "Registration Successful.";
$scope.formData = {};
} else if(response.data.registerSuccess == true) {
$scope.userform = "Registration Failed";
}
});
}
}]);
application.controller('logincontroller', ['$scope', '$http', '$location', '$rootScope', function($scope, $http, $location, $rootScope) {
$scope.loginData = {};
$scope.loginUser = "";
$scope.login = function() {
$http({
method: 'POST',
url: './services/loginservice.php',
data: $scope.loginData
}).then(function(response) {
console.log(response);
if(response.data.UsernameLogin == true) {
$scope.loginUser = "Invalid username or password.";
} else {
sessionStorage.setItem('userLogin', response.data.usernameSession);
$location.path('/customerHome');
}
});
}
}]);
Here is my loginservice.php
<?php
include '../connection/connect.php';
$formLogin = json_decode(file_get_contents("php://input"));
$data = array();
$check_UsernameLogin = false;
$username = $formLogin->username;
$password = $formLogin->password;
$login = mysqli_query($conn, "SELECT username FROM customer WHERE username='$username' AND customer_password='$password'");
$check_username = mysqli_num_rows($login);
if($check_username == 0) {
$check_UsernameLogin = true;
} else {
$check_UsernameLogin = false;
}
$data["UsernameLogin"] = $check_UsernameLogin;
$data["usernameSession"] = $login;
echo json_encode($data);
?>
Here is my login.html
<!-- Navigation Bar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#!/">Hostelry Service</a>
</div>
<ul class="nav navbar-nav">
<li>Home</li>
<li>Hostelries</li>
<li>Compare</li>
<li>About Us</li>
<li>Contact</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><span class="glyphicon glyphicon-user"></span> Sign Up</li>
<li><span class="glyphicon glyphicon-log-in"></span> Login</li>
</ul>
</div>
</nav>
<div class="row" style="padding-top: 100px;">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-primary">
<div class="panel-heading" style="padding-left: 190px;">Log in</div>
<div class="panel-body">
<form method="POST" ng-submit="login()">
<input class="form-control" type="text" ng-model="loginData.username" placeholder="Username"><br>
<input class="form-control" type="password" ng-model="loginData.password" placeholder="Password"><br>
<button type="submit" class="btn btn-primary btn-block">Submit</button><br>
<p class="alert alert-success" ng-show="loginUser">{{loginUser}}</p>
</form>
</div>
</div>
</div>
Here is my customerHomepage.html
<!-- Navigation Bar -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#!/">Hostelry Service</a>
</div>
<ul class="nav navbar-nav">
<li>Home</li>
<li>Hostelries</li>
<li>Compare</li>
<li>About Us</li>
<li>Contact</li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><span class="glyphicon glyphicon-user"></span> Sign Up</li>
<li><span class="glyphicon glyphicon-log-in"></span> Login</li>
</ul>
</div>
</nav>
<div class="row" style="padding-top: 100px;">
<div class="col-md-4 col-md-offset-4">
<div class="panel panel-primary">
<div class="panel-heading" style="padding-left: 190px;">Log in</div>
<div class="panel-body">
<form method="POST" ng-submit="login()">
<input class="form-control" type="text" ng-model="loginData.username" placeholder="Username"><br>
<input class="form-control" type="password" ng-model="loginData.password" placeholder="Password"><br>
<button type="submit" class="btn btn-primary btn-block">Submit</button><br>
<p class="alert alert-success" ng-show="loginUser">{{loginUser}}</p>
</form>
</div>
</div>
</div>
I am new to using .run() and $rootScope on angularjs.
In the application.run() , you need to check for state change and prevent or allow state change based on whether the user is logged in or not.For ex:
$rootScope.$on('$stateChangeStart', function (event, toState){
if(toState.name === 'login'){
return;
}
else if (!session.getAccessToken()) {
$state.go('login');
event.preventDefault();
}
else{
return;
}
});
Here session is a service.It checks if the access token is found in the session storage.If not found then it prevents user from going to inner pages.
Now,after making a call to login API from your login page,store the access token form the response into your session storage,and change the state to your desired home page.
NOTE: You might prefer using local storage instead of session storage for storing the access token.
To do this with PHP, you need to save user credentials (or login status) to $_SESSION and verify them everytime you serve a file. You need to give your files php extension for compatibility.
Set you index.php to call itself on form submission.
When called with the user name and password, authenticate them, and set the $_SESSION['authenticated'] variable to true in case of authentic login.
Now check this $_SESSION variable everytime you serve your templates.
<?PHP
if ($_SESSION['authenticated'] == false)
die('Permission denied');
?>
However, although it works, there are lot of new and more secure ways to handle this via methods such as jwt.

Angular UI-Router: nested views

I have two col layout with header and footer. Header has page navigation (GetStarted, Component). Of the 2 columns, one is for sidenav and other is for main content.
When "GetStarted" nav is active, sidenav is populated with respective links (overview, examples)
When "Component" nav is active, sidenav is populated with respective links (checkbox, alert)
Upon clicking "Overview" link area is populated with its data
<ul class="nav nav-tabs">
<li role="presentation" class="active">Default</li>
<li role="presentation">Disabled</li>
</ul>
<section class="content__main__tab__content col-xs-12 col-sm-12 col-md-12 col-lg-12">
<form id="checkbox--default">
<div class="input__checkbox--default" id="checkbox--default">
<!-- <div class="form-group"> -->
<fieldset>
<legend>Default</legend>
<label for="gi-checkbox">Checkbox Label
<div class="checkbox-input-wrapper group__input-wrapper">
<input type="checkbox" class="checkbox" id="gi-checkbox">
</div>
</label>
</fieldset>
<!-- </div> -->
</div>
</form>
</section>
Main content has 2 nav tabs for checbox states (default & disable). By clicking the "default" its content must be displayed and same goes for disabled. I'm new to angular and I kinda got first level nested view working. But couldn't the whole thing working. here is the code sample
index.html
<body ng-app="mendouiApp" id="mendo__home" data-spy="scroll" data-target=".scrollspy">
<nav class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" ui-sref="home"><img src="images/gi-logo.png" alt="logo"/></a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a ui-sref="home">Get Started</a></li>
<li><a ui-sref="components">Components</a></li>
</ul>
</div><!-- /.nav-collapse -->
</div><!-- /.container -->
</nav><!-- /.navbar -->
<div class="wrapper" ui-view></div> <!--/.container-->
component.html
<div class="content__wrapper">
<div class="row">
<div class="content__secondary content__secondary--l scrollspy">
<ul id="sidenav-fixed-l" class="nav hidden-xs hidden-sm affix-top" data-spy="affix">
<li>
<h5>COMPONENTS</h5>
</li>
<li ng-repeat="item in componentsList">
<a ui-sref="{{item.link}}" ng-cloak>{{item.name}}</a>
</li>
</ul>
</div>
<div ui-view></div>
</div> <!--/.row-->
</div> <!--/.content-wraper-->
app.js
(function(){
var mendouiApp = angular.module('mendouiApp', ['ui.router', 'ui.router.stateHelper']);
mendouiApp.constant('COMPONENTS_LIST', {
name: 'sidenav',
templateUrl: '../components/components.list.html',
abstract: true,
children: [{
name: 'alerts',
url: '/alerts',
templateUrl: '../components/alerts/alerts.html'
}]
});
mendouiApp.config(function($stateHelperProvider, $urlRouterProvider, $locationProvider, $urlMatcherFactoryProvider, COMPONENTS_LIST) {
$urlMatcherFactoryProvider.strictMode(false);
$urlRouterProvider.otherwise('/home');
$locationProvider.hashPrefix('!');
$stateHelperProvider
.state('home', {
url: '/home',
templateUrl: '../gettingstarted.html',
controller: 'getStartedController'
})
.state('layouts', {
url: '/layouts',
templateUrl: '../layouts.html'
})
.state('screenpatterns', {
url: '/screenpatterns',
templateUrl: '../screenpatterns.html'
})
.state('yogi', {
url: '/yogi',
templateUrl: '../yogi.html'
})
.state('components', {
url: '/components',
templateUrl: '../components.html',
controller: 'componentsController'
})
.state(COMPONENTS_LIST, {
keepOriginalNames: true
})
.state('components.button', {
url: '/button',
templateUrl: '../components/button/button.html'
}) .state('components.checkbox', {
url: '/checkbox',
templateUrl: '../components/checkbox/checkbox.html'
})
.state('components.forms', {
url: '/forms',
deepStateRedirect: true,
sticky: true,
views: {
'': { templateUrl: '..forms.html' },
'inline#components.forms': {
templateUrl: '../components/forms/form-inline/forminline.html'
},
'default#components.forms': {
templateUrl: '../components/forms/form-default/formdefault.html'
},
'multicolumn#components.forms': {
templateUrl: '../components/forms/form-multicolumn/formmulticolumn.html'
}
}
});
// use the HTML5 History API
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
});
mendouiApp.controller('componentsController', ['$scope', '$state', 'sideNavService', function($scope, $state, sideNavService, COMPONENTS_LIST){
$scope.componentsList = sideNavService.components;
$scope.componentsnav = COMPONENTS_LIST.children;
$scope.go = function(tab) {
$state.go(tab.name);
}
}]);
mendouiApp.controller('getStartedController', ['$scope', '$state', 'sideNavService', 'fixedSideNavService', function($scope, $state, sideNavService, fixedSideNavService ){
$scope.getstartedList = sideNavService.getstarted;
}]);
/*** This is for the external url reference ***/
mendouiApp.run(function($rootScope, $state, $stateParams, $window, fixedSideNavService, copyToClipBoardService) {
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams, $state, $stateParams) {
if (toState.external) {
event.preventDefault();
$window.open(toState.url, '_self');
}
});
$rootScope.$on('$viewContentLoaded', function(event){
fixedSideNavService.fixedsidenav();
copyToClipBoardService.copytoclipboard();
});
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$state.transitionTo('home');
});
})();
service.js
angular.module('mendouiApp').service('sideNavService', function() {
return {
"getstarted" : [
{
"name" : "Overview",
"link" : "home.overview"
}
{
"name" : "Summary",
"link" : "home.overview"
}
],
"components" : [
{
"name" : "Alerts",
"link" :"components.alert"
},
{
"name" : "Button",
"link" :"components.button"
},
{
"name" : "Button Groups",
"link" :"components.buttongroup"
},
{
"name" : "Button Icons",
"link" :"components.buttonicons"
},
{
"name" : "Checkbox",
"link" :"components.checkbox"
},
{
"name" : "Datepicker",
"link" :"components.datepicker"
},
{
"name" : "Forms",
"link" : "components.forms"
}
]
};
});
Your question was a bit messy, but after a while playing with I could understand I made this fiddle: http://jsfiddle.net/canastro/c4kt2myc/2/ I hope it works as you were expecting.
The main thing to focus on here is:
.state("root.components.button", {
url: '/components/button',
views: {
'main#': {
template: `
<div>
<a ui-sref="root.components.button.default">default</a>
<a ui-sref="root.components.button.disabled">disabled</a>
<div ui-view="buttonsContent"></div>
</div>
`
}
}
})
.state("root.components.button.default", {
url: '/components/button/default',
views: {
'buttonsContent#root.components.button': {
template: 'root.components.button.default'
}
}
})
.state("root.components.button.disabled", {
url: '/components/button/disabled',
views: {
'buttonsContent#root.components.button': {
template: 'root.components.button.disabled'
}
}
})
In the first level you have a abstract route so you can always have your basic layout present.
Then in the Started / Components routes, you load content into the main and side ui-views.
In all of the Started and Component child routes you just override the main views.
And finally, in the last level you need to say you want to fill the content of a ui-view created in the previous state, by doing something like VIEWNAME#STATENAME.

$scope not displaying data

The $scope data is not displaying on the page.
I have 2 views that are using the same controller.
I have this view, and I'm clicking the edit issue button
<div class="container" data-ng-init="adminInit()">
<div class="row">
<div class="col-lg-12">
<div class="page-header text-center">
<h1>Issues Admin</h1>
<button type="button" class="btn btn-primary" ui-sref="add-issue">
Add Issue
</button>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>Current Issues</h3>
<ul ng-repeat="issue in issues">
<li>
<strong>{{issue.title}}</strong> - Current Status:
<strong>{{issue.status}}</strong>
<div ng-hide="true" class="btn btn-xs btn-primary glyphicon glyphicon-pencil" ng-click="editIssue(issue._id)"></div>
<div class="btn btn-xs btn-primary glyphicon glyphicon-pencil" ng-click="editIssue(issue._id)"></div>
<div class="btn btn-xs btn-danger glyphicon glyphicon-remove" ng-click="deleteIssue(issue._id)"></div>
</li>
<ul>
<li>{{issue.description}}</li>
<li>Issue Logged at: {{issue.timestamp | date:'MM/dd/yyyy # h:mma'}}</li>
</ul>
</ul>
</div>
</div>
</div>
And this in my controller
$scope.editIssue = function(id) {
$state.go('edit-issue');
$http.get(Configuration.API + 'api/issue/' + id)
.then(function successCallback(response) {
$scope.issueToEdit = response.data;
console.log($scope.issueToEdit);
});
};
then the edit-issue view
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="page-header text-center">
<h1>Edit Issue</h1>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form name="frm" ng-submit="updateIssue()">
<div class="form-group">
<label for="editIssueTitle">Issue Title</label>
<input type="text" name="editIssueTitle" id="editIssueTitle" class="form-control" ng-model="issueToEdit.title" required/>
</div>
<div class="form-group">
<label for="editIssueDesc">Issue Description</label>
<textarea name="editIssueDesc" id="editIssueDesc" class="form-control" cols="60" rows="16" ng-model="issueToEdit.description" required></textarea>
</div>
<div class="form-group">
<label for="editIssueStatus">Issue Status</label>
<select name="editIssueStatus" id="editIssueStatus" class="form-control" ng-model="issueToEdit.status" required>
<option value="Identified">Identified</option>
<option value="Investigating">Investigating</option>
<option value="Monitoring">Monitoring</option>
<option value="Resolved">Resolved</option>
</select>
</div>
<button class="btn btn-default" ng-disabled="frm.$invalid">Go</button>
</form>
</div>
</div>
</div>
But the issueToEdit data is never displayed
The console.log line displays the right data
{
"_id": "58135b6e3987b8a90c4fc15b"
"title": "Test"
"description": "Testset"
"timestamp": "2016-10-28T14:06:38.284Z"
"status": "Monitoring"
"__v": 0
}
Any idea why this is happening?
EDIT: Let me clarify a little, when I land on the edit-issue page, I want the issueToEdit data to displayed in the form so that I can then update the info and then save it.
EDIT2: Here is my full controller and app.js
app.controller('issuesController', ['$scope', '$http', '$state', '$interval', 'auth', 'Configuration', function($scope, $http, $state, $interval, auth, Configuration) {
$scope.isLoggedIn = auth.isLoggedIn;
$scope.getIssues = function() {
console.log('retrieving issues');
$http.get(Configuration.API + 'api/issue')
.success(function(data) {
$scope.issues = data;
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.addIssue = function() {
var nIssue = {
'title': $scope.newissue.title,
'description': $scope.newissue.description,
'timestamp': new Date(),
'status': $scope.newissue.status
}
$http.post(Configuration.API + 'api/issue', nIssue)
.success(function(data) {
$state.go('admin');
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.editIssue = function(id) {
$state.go('edit-issue');
$http.get(Configuration.API + 'api/issue/' + id)
.then(function successCallback(response) {
$scope.issueToEdit = response.data;
console.log($scope.issueToEdit);
});
};
$scope.updateIssue = function() {
//ToDo add this logic
};
$scope.deleteIssue = function(id) {
$http.delete(Configuration.API + 'api/issue/' + id)
.success(function(data) {
$scope.issues = data;
})
.error(function(data) {
console.log('Error: ' + data);
});
};
$scope.adminInit = function() {
$scope.getIssues();
$interval($scope.getIssues, 60000);
};
$scope.issueInit = function() {
$scope.getIssues();
$interval($scope.getIssues, 60000);
$(".devInfo").text(navigator.userAgent);
$(".flashVersion").text(FlashDetect.raw);
};
}]);
app.js
var app = angular.module('supportWebsite', ['ui.router']);
app.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/articles');
$stateProvider
.state('home', {
url: '/',
templateUrl: '/pages/issues/index.html',
controller: 'issuesController'
})
.state('admin', {
url: '/admin',
templateUrl: '/pages/issues/admin/index.html',
controller: 'issuesController',
onEnter: ['$state', 'auth', function($state, auth) {
if (!auth.isLoggedIn()) {
$state.go('login');
}
}]
})
.state('add-issue', {
url: '/admin/add-issue',
templateUrl: '/pages/issues/admin/add.html',
controller: 'issuesController',
onEnter: ['$state', 'auth', function($state, auth) {
if (!auth.isLoggedIn()) {
$state.go('login');
}
}]
})
.state('edit-issue', {
url: '/admin/edit-issue',
templateUrl: '/pages/issues/admin/edit.html',
controller: 'issuesController',
onEnter: ['$state', 'auth', function($state, auth) {
if (!auth.isLoggedIn()) {
$state.go('login');
}
}]
});
$locationProvider.html5Mode(true);
}]);
Your method tells the $state service to go to another state. That will replace the view by the view associated with the new state, create a new $scope, and a new controller instance using this new $scope.
So whatever you put in the $scope of the current controller is irrelevant and useless: the other state uses another $scope and another controller.
You need to pass the ID of the issue to edit as a parameter of the new state. And the controller of this new state (or one of its resolve functions) should use that ID to get the issue to edit.
If you want to stay on the same view, using the same controller and the same scope, then you shouldn't navigate to another state.

View not refreshing after successful http.get from factory (chained promises in use)

I have read more tutorials and posts on this particular subject than I care to admit but I still haven't been able to locate a solution. I need the view to refresh after the chained promise returns which is bound to $scope.p.devices. I have tried disabling cached views (still disabled) and a number of other solutions. Hoping someone on here can point me in the proper direction.
HTML:
Device List
<md-card>
<ion-content>
<div class="card-content">
<div class="device-content-detail"
collection-repeat="device in p.devices"
collection-item-height="136px"
collection-item-width="100%">
<div class="card-content">
<h1 class="md-title">
<span>
<i class="fa fa-crosshairs" aria-hidden="true"></i>
Device List
</span>
</h1>
{{device.name}}
</div>
</div>
</ion-content>
</md-card>
<md-list>
<md-card ng-if="!isAnimated" class="card-item" ng-repeat="device in p.devices track by $index">
<md-card-content>
<div class="card-content">
<h1 class="md-title">
<span>
Device List
<i class="fa fa-crosshairs" aria-hidden="true"></i>{{device.name}}
</span>
</h1>
<div class="device-content-detail">
<i class="fa fa-wifi" aria-hidden="true"></i>{{device.connected}}
<i class="fa fa-heartbeat" aria-hidden="true"></i>{{device.last_heard}}
</div>
</div>
</md-card-content>
</md-card>
Controller:
appControllers.controller('devicesCtrl', function ($scope,$state,$stateParams,$timeout,$mdDialog,$ionicHistory,$ionicLoading,particle,pDevices,safeparse) {
//$scope.isAnimated is the variable that use for receive object data from state params.
//For enable/disable row animation.
var debug = true;
$ionicLoading.show({
content: 'Getting Devices',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
$timeout(function () {
pDevices.getpDevices().then(function(data) {
$scope.p.devices = data;
if (debug) console.log(debug + 'time out got particle.io device list: ', $scope.p.devices);
$scope.isLoading = false;
if (debug) console.log(debug + 'time out complete, hiding ionicLoading: ');
$ionicLoading.hide();
}, function() {
$scope.p.showAlertDialog($event);
$scope.error = 'unable to load devices'
});
}, 2000);
$scope.initialForm = function () {
//$scope.isLoading is the variable that use for check statue of process.
$scope.isLoading = true;
$scope.isAnimated = $stateParams.isAnimated;
};// End initialForm.
$scope.$watch('p.devices', function (newVal, oldVal){
console.log(newVal, oldVal)
});
$scope.p = {
currentDevice: '',
deviceId: particle.setDevice(),
token: particle.setToken(),
devices: [],
getDevices: function () {
pDevices.getpDevices().then(function(deviceList) {
if (debug) console.log(debug + 'getDevices got particle.io device list: ', deviceList);
$scope.p.devices = deviceList.data;
});
},
// Select the current device for particle platform
setDevice: function (deviceId) {
if (deviceId) {
if (debug) console.log(debug + 'setDevice', deviceId);
$scope.p.deviceId = deviceId;
particle.setDevice(deviceId);
$scope.startup();
}
return $scope.p.deviceId;
}
};
showAlertDialog = function ($event) {
$mdDialog.show({
controller: 'DialogController',
templateUrl: 'confirm-dialog.html',
targetEvent: $event,
locals: {
displayOption: {
title: "No Devices Found.",
content: "Unable to load Device List.",
ok: "Confirm"
}
}
}).then(function () {
$scope.dialogResult = "You choose Confirm!"
});
}// End showAlertDialog.
$scope.initialForm();
});// End of controller Device.
And finally the factory being called:
appServices.factory('pDevices', function($http, localstorage) {
root_url = 'https://api.particle.io/v1/'
var getpDevices = function() {
return $http.get(root_url + 'devices').then(function(response){
console.log('pDevices getpDevices: ', response.data);
return response.data;
});
};
return {
getpDevices: getpDevices
};
});
Screenshot of what I get:
Turns out the problem was entirely in my HTML/SASS div tags as well as my object array which was not device but Object. This is working but needing some formatting corrections.
<ion-view cache-view="false" title="Device List">
<!--note list section-->
<ion-content id="device-list-content" class="bg-white">
<md-list>
<md-card class="card-item"
collection-repeat="Object in p.devices"
collection-item-height="136px"
collection-item-width="100%">
<md-divider></md-divider>
<md-card-content>
<div class="card-content">
<h1 class="md-title-device">
<span>
<i class="fa fa-crosshairs" aria-hidden="true"></i> {{Object.name}}
</span>
</h1>
<div class="device-content-detail">
<div ng-show="Object.connected">
<i class="fa fa-wifi" aria-hidden="true"></i>
<i class="fa fa-heartbeat" aria-hidden="true"></i>{{Object.last_ip_address}}
</div>
<div ng-show="!Object.connected">
<i class="fa fa-wifi" aria-hidden="true"></i>
<i class="fa fa-heart-o" aria-hidden="true"></i>{{Object.last_heard}}
</div>
</div>
</div>
</md-card-content>
</md-card>
</md-list>
</ion-content>

Error with viewing an ionic HTML page after routing through Angular JS

I wrote a code for for my app, when a I click on the toggle to reach the second page, the url changes it took me there but nothing is appeared, just a blank page no more,
here is the app.js code
angular.module("BloodDonationApp", [
"ionic",
])
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
if (window.cordova && window.cordova.plugins && window.cordova.plugins.keyboard) {
cordova.plugins.keyboard.hidekeyboardAccessoryBar(true);
}
if (window.statusBar) {
//org.apache.cordova.statusbar required
statusbar.styleDefault();
}
});
})
//****************ROUTES***************//
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
abstarct: true,
url: "/home",
templateUrl: "templates/home.html"
})
.state('home.feeds', {
url: "/feeds",
views: {
"tab-feeds": {
templateUrl: "templates/feeds.html"
}
}
})
.state('home.settings', {
url: "/settings",
views: {
"tab-settings": {
templateUrl: "templates/settings.html"
}
}
})
.state('requestDetails', {
url: "/RequestDetails/:id",
view: {
"mainContent": {
templateUrl: "templates/requestDetails.html"
}
}
})
.state('requestDetails.ClientRegister', {
url: "/Client-Register/:id",
view: {
"mainContent": {
templateUrl: "templates/ClientRegister.html"
}
}
});
//if name of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/home/feeds');
})
and here is the html code of the feeds page:
<ion-view ng-controller="FeedsCtrl as vm">
<ion-content class="has-header">
<div class="card" ng-repeat="requests in vm.feeds">
<div class="item item divider" ng-click="toggleGroup(requests)"
ng-class="{active: isGroupShown(requests)}">
<div class="row row-bottom">
<div class="col">
{{requests.type}}
</div>
<div class="col">
{{requests.unitNb}} Units
</div>
</div>
</div>
<div class="item-accordion"
ng-show="isGroupShown(requests)" ng-click="goToDetails()">
<div class="row">
<div class="col-top">
Since 7 s{{requests.Date}}
</div>
<div class="col col-center col-50 col-offset-8">
<br/>{{requests.HospName}}
<br/>
{{requests.Hosplocation}}
</div>
<div class="col col-bottom">
<a class="item item-icon-right">
<div class="row">
<i class="ion-icon ion-pinpoint "></i>
</div>
<div class="row">
{{requests.HospDistance}}4km
</div>
</a>
</div>
</div>
</div>
</div>
</ion-content>
</ion-view>
and the controller for feeds:
(function () {
'use strict';
angular.module('BloodDonationApp')
.controller('FeedsCtrl', ['BloodDonationApi', '$scope', '$state', FeedsCtrl]);
function FeedsCtrl(BloodDonationApi, $scope, $state) {
var vm = this;
//start Data Binding functions//
var data = BloodDonationApi.getRequests();
console.log(data);
vm.feeds = data;
//end Data Binding//
//start Accordion function//
$scope.toggleGroup = function (requests) {
if ($scope.isGroupShown(requests)) {
$scope.shownGroup = null;
} else {
$scope.shownGroup = requests;
}
}
$scope.isGroupShown = function (requests) {
return $scope.shownGroup === requests;
}
$scope.goToDetails = function() {
$state.go('requestDetails', {id : 5});
}
//end Accordion function//
};
})();
but the request details is not appeared after clicking on the toggle its just give a blanck page, the html code :
<ion-view ng-controller="RequestDetailsCtrl as vm">
<ion-content class="has-header">
<div class="card">
<div class="item">
<div class="row">
<div class="col">
{{requests.type}}
</div>
<div class="col">
{{requests.unitNb}} Units
</div>
</div>
<div class="row">
<div class="col">
{{requests.HospName}}
</div>
<div class="col">
{{requests.Hosplocation}}
</div>
<div class="col">
4 Km Away
</div>
</div>
<button class="button button-block button-positive">
Yes, I donate <i class="ion-icon ion-thumbsup"></i>
</button>
<label>
4/5 <i class="ion-icon ion-battery-half"></i>
</label>
<div class="title">
<h3>
Last time I'd donated was since<br /> 4 months
<i class="ion-icon ion-checkmark-round"></i>
</h3>
</div>
</div>
</div>
</ion-content>
</ion-view>
the controller:
(function () {
'use strict';
angular.module('BloodDonationApp')
.controller('RequestDetailsCtrl', ['BloodDonationApi', '$stateParams', '$scope', RequestDetailsCtrl]);
function RequestDetailsCtrl(BloodDonationApi, $stateParams, $scope) {
var vm = this;
var data = BloodDonationApi.getRequests();
console.log(data);
vm.requestDetails = data;
console.log("$stateParams", $stateParams.id);
//end Data Binding//
// Get you request
};
})();
am sure that there is an error with the view code, but m not figuring it out, if anybody can help me plz.
You are inside a nested state when you are tying to load requestDetails so change your state to :
.state('requestDetails', {...})
.state('home.requestDetails', {
url: "/feeds/:id",
views: {
'tab-feeds' :{
templateUrl: "templates/requestDetails.html"
}
}
})
and your method to:
$scope.goToDetails = function() {
$state.go('home.requestDetails', {id : 5});
}
and It's working !
I've fork your git so updated working version is here if you want to pull

Resources