AngularJS UI freeze during polling $timeout $scope updates - angularjs

I have an app with a simple view that contains a list of a few items.
<ion-view view-title="App">
<ion-content>
<div class="list">
<div ng-repeat="group in groups">
<div class="item item-divider">
{{group.name}}
</div>
<div class="item row" ng-repeat="item in group.items" ng-click="live(item.id)">
<div class="col-75">
</div>
<div class="col">
</div>
</div>
</div>
</div>
</ion-content>
</ion-view>
I fetch these items from a service that makes a $http get of a json array from the server, and inside the controller I need to update this list every 10 seconds.
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state("home", {
url: "/home",
templateUrl: "home.html",
controller: "homeCtrl",
resolve: {
data: function(appDataService){
return appDataService.getData();
}
}
})
;
$urlRouterProvider.otherwise("/home");
});
.factory('appDataService', function ($http) {
return {
getData: function () {
return $http.get(HOST + "/ionic-proof.ashx").then(function (response) {
return response;
});
},
};
})
.controller("homeCtrl", function($state, $scope, data, appDataService, $timeout){
$scope.groups = data.data.groups;
(function refresh(){
appDataService.getData().then(function(response){
$scope.groups = response.data.groups;
$timeout(refresh, 10000);
});
})();
$scope.live = function(id){
$state.go("event", {id: id});
};
})
The problem is, everytime the $scope.groups inside the refresh() function is executed, I get a short "freeze" in the UI, which is quite noticeable (e.g. if I am scrolling the list up and down).
Any ideas what I might be doing wrong?
Thanks in advance

Related

How to correctly reinitiate view with $state.go from another view

I am attempt to send users from one state to another with this method:
$state.go('splash');
This works correctly, however, when users are sent to my splash view the code does not reinitiate.
This is the html of the splash state:
<ion-view hide-nav-bar="true">
<ion-content class="splash-screen" scroll="false">
<div class="loading">
<i class="fa fa-circle-o-notch fa-spin fa-5x fa-fw"></i>
</div>
</ion-content>
</ion-view>
<script id="login.html" type="text/ng-template">
<ion-modal-view>
<ion-header-bar class="bar bar-header bar-stable">
<h1 class="title">Login</h1>
</ion-header-bar>
<ion-content>
<div class="list padding">
<div class="error" ng-if="errors">
<p ng-bind-html="error_message"></p>
</div>
<label class="item item-input">
<input ng-model="data.password" type="password" placeholder="Password">
</label>
<button class="button button-full button-positive" ng-click="login(data)">Login</button>
</div>
</ion-content>
</ion-modal-view>
</script>
This is the controller for the view:
angular.module('app.controllers', [])
.controller('SplashCtrl', function($scope, $http, $state, $ionicModal, $ionicLoading, $ionicPlatform, $timeout, $localstorage, appAPI) {
$scope.data = {};
$scope.data.password = '';
$ionicModal.fromTemplateUrl("login.html", {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.login = function(data) {
alert(data.password);
};
$ionicPlatform.ready(function() {
$scope.openModal();
});
});
When users visit the splash view the first time, the modal loads as intended, however, when they are directed there from the $state.go - the modal does not load.
Any thoughts how I can get this to work correctly?
Multiple Calls to $ionicPlatform.ready()
Unfortunately, other callbacks passed to the function are silently ignored. (ARGH!)1
In addition to taking a callback function as a parameter, it returns a promise for the platform being ready.
Use the promise:
$ionicPlatform.ready().then(function() {
$scope.openModal();
});
I hope you are looking to reload your 'SplashCtrl' controller when the user is routed to the 'splash' state.
If so, try this $state.go('splash', {}, {reload: true});
You haven't shared your entire project so I can't tell really. It seems your structure is a bit off. You should only have one ionicPlatform.ready() and it should be to setup the environment. Once done it should forward the user to your first view, no open a modal.
This is how I check that in my app. The platform ready function has $state.go('app.calendar'); which is my first view (assuming they are logged in) - if they are not logged in the init function returns an error from the promise and the statechange error code forwards them to the login signup page.
State controller
.state('app', {
url: '/app',
cache: false,
abstract: true,
templateUrl: 'templates/tabs.html',
controller: 'TabCtrl',
resolve: {
user: function (UserService) {
var value = UserService.init();
return value;
}
}
})
// Calendar
.state('app.calendar', {
url: "/calendar",
cache: true,
views: {
'calendar-tab': {
templateUrl: 'templates/calendar.html',
controller: 'CalendarController'
}
}
})
Check if logged in.
function init(){
var deferred = $q.defer();
if (loggedIn()) {
deferred.resolve(currentUser);
} else {
deferred.reject({error: "noUser"});
}
return deferred.promise;
};
React to the state error - app-first is the login or signup page.
$rootScope.$on('$stateChangeError',
function (event, toState, toParams, fromState, fromParams, error) {
console.log('$stateChangeError ' + error && (error.debug || error.message || error));
// if the error is "noUser" the go to login state
if (error && error.error === "noUser") {
event.preventDefault();
$state.go('app-first', {});
}
}
);

view detail in new page when click button using angularjs

I want to display the clicked row button details info in next view,I am displayin only code,nom in first page and remaining fields will view after clicking button.
I used the option "filter" to do it, but sometimes it returns details of non concerned code , like for the two codes: 45 and 453 , it gaves the same detail because of the common number '45'.
First html page:
<div class="row header">
<div class="col" >Code</div>
<div class="col">Client</div>
</div>
<div class="row" ng-repeat="x in namesC">
<div class="coll">
<a class="button" href="#/detail/{{x.Code}}">
{{x.Code}}</a>
</div>
<div class="col"> {{x.NomClient}} </div>
</div>
second html page (detail.html):
<ion-list ng-repeat="x in namesC| filter: {Code: thisX}|limitTo:1">
<ion-item>
<div class="item item-divider center-text"> {{x.Code}}</div>
</ion-item>
<ion-item>
<b>adresse</b> <span class="item-note"> {{x.adresse}} </span>
</ion-item>
</ion-list>
app.js :
$stateProvider.state('detailColis', {
url: '/detail/:Code',
templateUrl: 'templates/detail.html',
controller: 'SuiviAdminCtrl'
});
You must add Config file Or add the down code in html file to solve this problem
<script>
var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "main.htm"
})
.when("/detail/:Id", {
templateUrl : "detail.htm"
})
});
</script>
I tested the above code, its working.
We can use $routeParams, Also we can use service. See basic example and try like below.
var app = angular.module('exApp',['ngRoute']);
app.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
$routeProvider
.when('/', {
template:'<p>All Datas View</p><p ng-repeat="data in datas">{{data.name}} <button ng-click="setData(data)">View</button> routeParams.. <button ng-click="setrouteData($index)">Index</button></p>',
controller: 'ctrl',
})
.when('/detail',{template:'<p>Particular Data View</p><button ng-click="back()">Back</button><br><p>{{data}}</p>',controller: 'ctrlOne'})
.when('/detail/:id',{template:'<p>Data View</p><button ng-click="back()">Back</button><br><p>{{data}}</p>',
controller: 'ctrltwo'})
.otherwise({redirectTo:'/'});
}]);
app.controller('ctrl', function($scope,$location,exService){
$scope.datas = exService.data;
$scope.setData = function(data){
//console.log(data);
exService.Obj = data;
$location.path('detail');
}
$scope.setrouteData = function(index){
$location.path('detail/'+ index);
}
});
app.controller('ctrlOne', function($scope,$location, exService){
var data = exService.Obj;
$scope.data=data;
$scope.back = function(){
$location.path('/');
}
});
app.controller('ctrltwo', function($scope,$location, $routeParams,exService){
var data = $routeParams.id;
$scope.datas = exService.data;
$scope.data=$scope.datas[data];
$scope.back = function(){
$location.path('/');
}
});
app.service('exService', function(){
var Obj = {};
var data = [{"id":1, "name":"xxx"},{"id":2, "name":"yyy"},{"id":3, "name":"zzz"}];
return { Obj, data};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-route.min.js"></script>
<body ng-app="exApp">
<p>Sample</p>
<div ng-view></div>
</body>
this is the solution, Thanks to Sudarshan_SMD
The solution is just to change filter: with :
filter: {CodeEnvoiColis: thisX}:true

nested ui-router $location binding

I have some problem with binding when i use ui-router. I am trying to make the app modular and keep it clean and simple.
I have the following app.js
// main routing - index.html
var app = angular.module('mainApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('index', {
url: '/',
templateUrl: 'pages/main.html'
})
.state('cars', {
url: '/cars',
templateUrl: 'pages/Cars_model/main.html'
})
.state('cars.audi', {
url: '/audi',
templateUrl: 'pages/Cars_model/audi.html'
})
.state('cars.ford', {
url: '/ford',
templateUrl: 'pages/Cars_model/ford.html'
})
});
app.controller('indexController', function($scope, $location) {
$scope.isIndexPage = function() {
return $location.path() === '/';
}
});
app.controller('carsCtrl', function($scope, $location) {
if($location.path() === '/cars/audi')
{
$scope.pageHeader = "AUDI";
$scope.curentMenu = "Best Cars";
$scope.title = "Audi Specs";
}
if($location.path() === '/cars/ford')
{
$scope.pageHeader = "FORD";
$scope.curentMenu = "Best Cars";
$scope.title = "Ford Specs";
}
});
and the file where i want to use binding
<div class="container" ng-controller="carsCtrl">
<div class="page-header">
<h1>{{pageHeader}}</h1>
</div>
<!-- The first row -->
<div class="row">
<div class="col-lg-12 col-md-12 col-sd-12">
<ol class="breadcrumb">
<li>Home</li>
<li>{{curentMenu}}</li>
<li class="active">{{pageHeader}}</li>
</ol>
</div>
</div>
</div>
The problem is when i load the page the binding work only once, for the second i have to refresh the page.
I am not sure if i used the corect logic
if($location.path() === '/cars/ford')
I think i found the solution
Using
ui-sref-opts="{reload: true}"
in the menu solve the problem
<a ui-sref="cars.audi" ui-sref-opts="{reload: true}">Audi</a>
Plunker

Show clicked image from flickr with tags and comments AngularJS

I have to make app for listing recent photos from Flickr with option when click on any image to show that image with tags and comments it contains.
I've made this:
core.module.js
(function () {
'use strict';
angular.module('flickrApp.core', ['ui.router', 'ngResource']);
})();
core.factory.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.factory('flickrImgs', flickrImgs);
flickrImgs.$inject = ['$http'];
function flickrImgs($http) {
var url = 'https://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=415028ef16a31ed8f70f9dc3e90964d1&extras=url_q,url_o,tags&format=json&nojsoncallback=1';
var photos;
var factory = {
getPhotos: getPhotos
};
return factory;
function getPhotos() {
return $http.get(url).then(function (response) {
factory.photos = response.data.photos.photo;
});
}
};
})();
core.controller.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.controller('flickrController', flickrController);
flickrController.$inject = ['flickrImgs', '$location', '$http'];
function flickrController(flickrImgs, $location, $http) {
var fc = this;
fc.showImg = function (id) {
$location.path("/photos/" + id);
console.log(id);
};
flickrImgs.getPhotos().then(function () {
fc.photos = flickrImgs.photos;
});
}
})();
core.router.js
(function () {
'use strict';
angular
.module('flickrApp.core')
.config(config);
config.$inject = ['$stateProvider', '$urlRouterProvider'];
function config($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('main', {
abstract: true,
views: {
'header': {
templateUrl: 'app/components/core/header.html'
}
}
})
.state('main.home', {
url: '/home',
views: {
'content#': {
templateUrl: 'app/components/core/home.html',
controller: 'flickrController',
controllerAs: 'fc'
}
}
})
.state('main.singleImg', {
url: '/photos/:id',
views: {
'content#': {
templateUrl: 'app/components/core/single-img.html',
controller: 'flickrController',
controllerAs: 'fc'
}
}
});
newPhoto.$inject = ['$stateParams', 'flickrImgs'];
function newPhoto($stateParams, flickrImgs) {
return flickrImgs.get({
id: $stateParams.id
}).$promise;
}
}
})();
home.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | limitTo:16" class="col-sm-12 col-md-3">
<a href ng-click="fc.showImg(photo.id)">
<img class="thumbnail" ng-src="{{photo.url_q}}" width="100%">
</a>
</div>
</div>
single-img.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | filter : {id: photo.id} | limitTo: 1" class="col-sm-12 col-md-10 col-md-offset-1">
<a href ng-click="fc.showImg(photo.id)">
<img class="thumbnail" ng-src="{{photo.url_o}}" width="100%">
</a>
<div>Tags:
<button class="btn-primary">
{{photo.tags}}
</button>
</div>
<div>Comments:
<div>
{{photo.comments}}
</div>
</div>
</div>
</div>
When I click on image listed on home page, I want to pass that image to single-img.html template and I get image id in url, but I don't know how to pass it to html.
Any help would be appreciated.
You are missing ui-sref in in home.html
<div class="row col-sm-12 col-md-10 col-md-offset-1">
<div ng-repeat="photo in fc.photos | limitTo:16" class="col-sm-12 col-md-3">
<a ui-sref="main.singleImg({id: photo.id})">
<img class="thumbnail" ng-src="{{photo.url_q}}" width="100%">
</a>
</div>
</div>
// Updated flickrImgs factory method
function getPhotos() {
var deferred = $q.defer();
if (factory.photos) {
deferred.resolve(factory.photos);
} else {
$http.get(url).then(function(response) {
factory.photos = response.data.photos.photo;
deferred.resolve(factory.photos);
});
}
return deferred.promise;
}
// single image state with new controller
.state('main.singleImg', {
url: '/photos/:id',
views: {
'content#': {
templateUrl: 'app/components/core/single-img.html',
controller: 'singleImgController',
controllerAs: 'sic'
}
}
});
// New Controller
angular
.module('flickrApp.core')
.controller('singleImgController', singleImgController);
singleImgController.$inject = ['$stateParams', 'flickrImgs'];
function singleImgController($stateParams, flickrImgs) {
var vm = this;
flickrImgs.getPhotos()
.then(function(photos) {
angular.forEach(photos, function(photo) {
if(photo.id == $stateParams.id) {
vm.photo = photo;
}
})
});
}
// New single-img.html
<div class="row col-sm-12 col-md-8 col-md-offset-2">
<img class="thumbnail" ng-src="{{sic.photo.url_o}}" width="100%">
<div>Tags:
<div class="btn-primary">
{{sic.photo.tags}}
</div>
</div>
<div>Comments:
<div>
{{sic.photo.comments}}
</div>
</div>
</div>
Hope this helps.

Can't get an object shared between controllers

I'm trying to share an object between two controllers with a factory. I can store the object correctly but when I try to get it from the main controller it says the object it's empty(undefined). I would appreciate some feedback.
var app = angular.module('wgot', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('splash', {
url: "/",
templateUrl: "templates/splashscreen.html"
})
.state('settings', {
url: "/settings",
templateUrl: "templates/settings.html"
})
.state('main', {
url: '/main',
templateUrl: 'templates/main.html'
})
$urlRouterProvider.otherwise('/');
})
.factory('TT', function(){
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
})
.controller('SettingsCtrl', function($scope, $http, TT){
$scope.regions = [
{name : 'United Arab Emirates', id : '23424738'}
];
$scope.region = $scope.regions[0];
$scope.requestTT = function() {
$http.get(/* url */ + $scope.region.id).success(function (data){
TT.set(data);
})
};
})
.controller('MainCtrl', function($scope, TT){
//Here TT.get() doesn't return the value that I've stored previously
$scope.words = TT.get();
var words = [];
var listLength = $scope.words.list[0]['trends'].length;
for (var i = 0; i < listLength; i++) {
words[i] = $scope.words.list[0]['trends'][i].name;
};
this.words = words;
});
This are the views:
<ion-view class= "splashscreen" ng-controller="SettingsCtrl">
<ion-content class = "content" scroll="false">
<div class="bar bar-header bar-light">
<h1 class="title">Settings</h1>
</div>
<div class="list card list-card">
<label class="item item-input item-select">
<div class="input-label">
Country
</div>
<select ng-model="region" ng-options="region.name for region in regions">
<option value="">-- choose a region --</option>
</select>
</label>
<a class="item item-icon-right assertive" ui-sref="main" ng-click="requestTT()">
<i class="icon ion-radio-waves"></i>
Start receiving
</a>
</div>
</ion-content>
</ion-view>
This second controller is the one that can't get the object.
<ion-view class = "main">
<ion-content>
<div class="os-phrases" ng-controller="MainCtrl as main">
<h2 ng-repeat="word in main.words" ng-bind-html='word | lettering'></h2>
</div>
</ion-content>
</ion-view>
I think the problem is that by the time you read the data from the service in the Main controller, nothing has been assigned to it yet, one way to work around this would be to watch the data in the service inside your Main controller:
$scope.$watch(TT.get,function(v){
$scope.words = v;
})

Resources