I am having an issue displaying response data, returned from my factory,inside an ionic view page. I believe the issue has something to do with the way I am handling the promise, but I cannot pinpoint why. So to start the roadmap to my problem, here is my:
Factory
.factory('profileFactory', function ($http, $q) {
var config = {
headers: {
'MyKey': 'myvalue'
}
};
this.getEmployee = function (userId) {
return $http.get('http://someurlpathtogoto' + userId + 'etc', config).then(function (response) {
console.log(response.data)
return response.data;
})
}
return this;
})
The above code returns the JSON object I need for my controller so:
Controller
.controller('EmployeeCtrl', ['$scope', 'profileFactory', function ($scope, profileFactory) {
//Set back to false
$scope.profileLoaded = true;
$scope.serviceUnavailable = false;
$scope.setId = function (userId) {
profileFactory.getEmployee(userId).then(function(arrItems){
$scope.employee = arrItems;
$scope.firstName = $scope.employee.record[0].First_Name;
$scope.lastName = $scope.employee.record[0].Last_Name;
};
}])
Now when my page displays I want it to look like such:
Ionic View (Profile)
<ion-view view-title="Profile" ng-controller="EmployeeCtrl" hide-nav-bar="true">
<ion-pane>
<!-- TODO: BACK BUTTON, NO TITLE -->
<ion-header-bar class="bar-stable">
<h1 class="title">Ionic Blank Starter</h1>
</ion-header-bar>
<ion-content>
<div ng-show="serviceUnavailable">
Directory service unavailable
</div>
<div ng-show="profileLoaded">
<br />
<center><img class="focus-img-circle" ng-src="default.png" /></center>
<center><b>{{firstName}} {{lastName}}</b></center>
</div>
</ion-content>
</ion-pane>
<ion-view>
All of this is invoked whenever a user presses on an arrow button in the app which should take them to their profile page to view some info. The following code appears in the previous view.
Ionic View (Search Results)
<ion-item class="item item-avatar item-button-right" ng-repeat="user in results" ng-controller="EmployeeCtrl">
<img ng-src="data:image/png;base64,{{user.pic}}">
<strong>{{user.first_name}} {{user.last_name}}</strong>
<div class="buttons" style="padding:20px;">
<button type="button" class="button button-icon ion-ios-telephone-outline customSearchIcon" ng-click=""></button>
<a class="button button-icon ion-ios-arrow-right customSearchIcon" ng-click="setId(user.id)" href="#/tab/search/profile"></a>
<button type="button" class="button button-icon ion-ios-heart-outline customSearchIcon" ng-click="addFavorite(user.id, user.first_name, user.last_name, user.pic)"></button>
</div>
</ion-item>
So essentially a user clicks on a persons tab, takes them to that profile where my factory is used to make a RESTful call to return a JSON object containing data about that user. Except nothing is being displayed in the Ionic View. If I hard code a userId in the controller and take away the function setId() it works but that obviously isn't an option. Does anyone see anything specifically that I am doing wrong? Been stuck on this for hours any help would be great.
I left a lot of code out to get my point across.
EDIT
The two views you see are different ionic templates. So using ng-controller="EmployeeCtrl is not happening twice in the same view.
The mistake is, on arrow click, you call the service and store the data to scope variable and then navigates to second view. The second view though uses the same controller as the first view, a new controller is being instantiated with empty scope - and hence your view is empty.
Instead of ng-click in <a> tag, modify your profile route to pass the userid as well - tab/search/profile/:userid and in anchor tag have ng-href= "#/tab/search/profile/{{user.id})" and in your profile controller get the userid from query string ($location.search().userid) and make the Ajax call.
Related
So I am trying to configure my application in a way that lets it route dynamically depending on the servers response. My code is as follows.
HTML
<div ng-controller="CategoriesController" class="column">
<div layout-align="center center" ng-repeat="category in categories" >
<div class="category-button-text-english">{{category}}</div>
<md-button ng-click="submit()" class="category-button" aria-label="{{category}}">
<img ng-src="assets/images/categories/{{category}}.png"
alt="{{category}}">
</md-button>
<div class="category-button-text-translation">
{{category|uppercase| translate}}
</div>
Controller
$scope.submit=function(){
subCategoryService.getsubCategories().then(function (response)
{
console.log(response)
$rootScope.subcategories=response.data.data.subcategories;
$scope.category=response.data.data.category_name;
})
$location.path('/subcategory');
}
Service
.factory('subCategoryService', ['$http', '$httpParamSerializerJQLike', '$cookies','$rootScope', function ($http, $httpParamSerializerJQLike, $cookies,$rootScope,category){
var url2 = 'localhost:5000/api/subcategories/';
return {getsubCategories: function () {
return $http.get(url2);
}}}])
Another controller that gives the category names from server's response before the application comes on category page.
controller("userTypeController", function ($rootScope,$scope, $location, CategoryService) {
$scope.getCat=function(){
CategoryService.getCategories() .then(function (response)
{
$rootScope.categories=response.data.data.categories;
});
$location.path('/category');
};
So what I want is that after getting the category names from the server, it calls the right route depending on what button is clicked on the category page. For example depending on what button is clicked, the call should go like
localhost:5000/api/subcategories/CATEGORY_NAME. I get an array of categories when I go through the user type service and I want to use one of those category names to be passed in the subcategory service just as I wrote earlier. The flow of the application is like User->Category->Depending on category, show the subcategories. Any help would be appreciated. Thanks !!
Use like this
Route
.when("/category/:category_name", {
....
....
})
Service
.factory('subCategoryService', ['$http', '$httpParamSerializerJQLike', '$cookies','$rootScope', function ($http, $httpParamSerializerJQLike, $cookies,$rootScope,category){
var url2 = 'localhost:5000/api/subcategories/'+httpParamSerializerJQLike.category_name;
return {getsubCategories: function () {
return $http.get(url2);
}}}])
I have to display a list of products and be able to click on them to get more informations about them.
My list of products is stored in a service named: "productsServices"
I got an html page who display all my products and an other who display details for 1 product. Each html page have their own controller.
When I update a product in my detail page, the changement is done in my productsServices but are not validated in my global product view.
(function ()
{
angular.module('app').service('productsServices', ['$http', '$q', ProductsServices])
that = this
that.products = /*arrayOfData*/;
that.getProducts = function () {
return that.products;
}
})();
(function ()
{
angular.module('app').controller('ProductsController', ['$http', '$q', 'productsServices', ProductsController])
that = this
that.products = productsServices.getProducts;
that.showDetail = function (item) {
$state.go('menu.product', { myParam: item });
}
})();
<!--Global HTML page-->
<ion-content id="content" class="has-header has-subheader" delegate-handle="myScroll">
<ion-list>
<ion-item ng-repeat="product in that.products() track by product.ProductId" href="#" ng-click="that.showDetail({{product}})">
<div class="innerProd">
<img id="productPicture" name="productPicture" ng-src='data:image/png;base64,{{product.ThumbnailPhoto}}'></div>
<div class= "innerProd">
<p>{{product.Name}}</p>
<p>{{product.Price}}$</p>
<ion-option-button class="button button-assertive"
ng-click="doDelete({{product}})">
Supprimer
</ion-option-button>
</div>
</ion-item>
</ion-list>
<ion-infinite-scroll ng-if="moreDataCanBeLoaded()" icon="ion-loading-c" on-infinite="loadMoreData()" distance="100%">
</ion-infinite-scroll>
</ion-content>
So when I check the product sended in the "that.showDetail" method, it's the old product who is sended even if the product have been updated in the services.
I'm not english so sorry for language mistakes in my sentence ^^'
Thank in advance for your help ^^'
Ok I've find the ansewer to my question, I've replace the parameter that I'm sending to my "that.showDetail" function. I'm no more sending the object directly, but the index of my item.
<ion-item ng-repeat="product in that.products() track by product.ProductId" href="#" ng-click="that.showDetail({{$index}})">
I guess that angular doesn't update injected in a ng-click call ^^'
Thank you for your time guys
I am new to Angular and need your help on an issue with the ng-repeat of my app.
Issue:
I have an html page (event.html) and in the corresponding controller of the file, I make a request to a firebase collection and update an array ($scope.events). The issue is that the data from firebase takes a few seconds to load and by the time data arrives to $scope.events, ng-repeat has already been executed and it displays an empty screen. The items are displayed correctly the moment I hit on a button in the HTML page (event.html).
Sequence of events:
I have a login page (login.html) where I enter a user name and phone number and I click on the register button. I've configured this click on the register button to go to the new state (event.html).
Here is the controller code for login.html:
$scope.register = function (user) {
$scope.user = user.name;
$scope.phonenumber = user.phonenumber;
var myuser = users.child($scope.user);
myuser.set({
phone : $scope.phonenumber,
Eventid : " ",
name : $scope.user
})
var userid = myuser.key();
console.log('id is ' +userid);
$state.go('event');
}
The controller of event.html (the state: event) has the following code:
var ref = new Firebase("https://glowing-torch-9862.firebaseio.com/Users/Anson/Eventid/");
var eventref = new Firebase("https://glowing-torch-9862.firebaseio.com/Events");
var myevent = " ";
$scope.events = [];
$scope.displayEvent = function (Eventid) {
UserData.eventDescription(Eventid)
//UserData.getDesc()
$state.go('myevents');
//console.log(Eventid);
};
function listEvent(myevents) {
$scope.events.push(myevents);
console.log("pushed to array");
console.log($scope.events);
};
function updateEvents(myevents) {
EventService.getEvent(myevents);
//console.log("success");
};
ref.once('value', function (snapshot) {
snapshot.forEach(function (childSnapshot) {
$scope.id = childSnapshot.val();
angular.forEach($scope.id, function(key) {
eventref.orderByChild("Eventid").equalTo(key).on("child_added", function(snapshot) {
myevents = snapshot.val();
console.log(myevents) // testing 26 Feb
listEvent(myevents);
updateEvents(myevents);
});
});
});
});
$scope.createEvent = function () {
$state.go('list');
}
event.html contains the following code:
<ion-view view-title="Events">
<ion-nav-buttons side="primary">
<button class="button" ng-click="createEvent()">Create Event</button>
<button class="button" ng-click="showEvent()">Show Event</button>
</ion-nav-buttons>
<ion-content class="has-header padding">
<div class="list">
<ion-item align="center" >
<button class= "button button-block button-light" ng-repeat="event in events" ng-click="displayEvent(event.Eventid)"/>
{{event.Description}}
</ion-item>
</div>
</ion-content>
</ion-view>
The button showEvent is a dummy button that I added to the HTML file to test ng-repeat. I can see in the console that the data takes about 2 secs to download from firebase and if I click on the 'Show Events' button after the data is loaded, ng-repeat works as expected. It appears to me that when ng-repeat operates on the array $scope.events, the data is not retrieved from firebase and hence its empty and therefore, it does not have any data to render to the HTML file. ng-repeat works as expected when I click the dummy button ('Show Event') because a digest cycle is triggerred on that click. My apologies for this lengthy post and would be really thankful if any of you could give me a direction to overcome this issue. I've been hunting in the internet and in stackoverflow and came across a number of blogs&threads which gives me an idea of what the issue is but I am not able to make my code work.
Once you update your events array call $scope.$apply(); or execute the code that changes the events array as a callback of the $scope.$apply function
$scope.$apply(function(){
$scope.events.push(<enter_your_new_events_name>);
})
If you are working outside of controller scope, like in services, directive, or any external JS. You will need to trigger digest cycle after change in data.
You can trigger digest cycle by
$scope.$digest(); or using $scope.$apply();
I hope it will be help you.
thanks
In your case you have to delay the binding time. Use $timeout function or ng-options with debounce property in your view.
you have to set a rough time taken to get the data from the rest API call. By using any one of the methods below will resolve your issue.
Method 1:
var myapp = angular.module("myapp", []);
myapp.controller("DIController", function($scope, $timeout){
$scope.callAtTimeout = function() {
console.log("$scope.callAtTimeout - Timeout occurred");
}
$timeout( function(){ $scope.callAtTimeout(); }, 3000);
});
Method 2:
// in your view
<input type="text" name="userName"
ng-model="user.name"
ng-model-options="{ debounce: 1000 }" />
What I want
I have 3 views. All views have their own controller. The first view is home. From the home view the user goes to view 2 by clicking on a div element. On view 2 the user opens view 3 by clicking on a button. On view 3 the user clicks on a button and goes back to view 2.
The problem I am facing is that I want to know if the user came from view 2. In that case I want to show different content then when the user came from the home view.
Create another view
Can it be done without creating another view?
My try
I created a service that keeps track of if I came from view 3, but the controller of view 2 isn't executed anymore after view 2 got opened from the home view. So basicly $scope.fromViewThree isn't updated and still false.
I added $route.reload() before $window.location = "#/app/viewtwo"; because I thought it would reinitialise the controllers(source) and then $scope.fromViewThree should have been updated. I also tried adding it below $window.location = "#/app/viewtwo";.
Controller view 2
.controller('ViewTwoCtrl', function($scope, $window, fromViewThree) {
$scope.fromViewThree = fromViewThree.getBoolean();
fromViewThree.setBoolean(false);
$scope.goToViewThree = function() {
$window.location = "#/app/viewthree";
};
})
Controller view 3
.controller('ViewThreeCtrl', function($scope, $window, fromViewThree) {
$scope.goToViewTwo = function() {
fromViewThree.setBoolean(true);
$window.location = "#/app/viewtwo";
};
})
Directives.js
.service('fromViewThree', function () {
var b = false;
return {
getBoolean: function() {
return b;
},
setBoolean: function(value) {
b = value;
}
};
})
HTML view 2
<div ng-if="fromViewThree == false">
<p>You came from view home!</p>
</div>
<div ng-if="fromViewThree == true">
<p>You came from view three!</p>
</div>
<div>
<button ng-click="goToViewThree()" ng-if="fromViewThree == false">Go to view 3</button>
<button ng-click="goToViewThree()" ng-if="fromViewThree == true">Go again to view 3</button>
</div>
HTML view 3
<div class="row">
<button class='button' ng-click="goToViewTwo()">Lets go to view two!</button>
</div>
Try implementing the views and controllers using the UI router. Once you have the states setup, accessing the previous state will be easy Angular - ui-router get previous state
Solution
Manu Antony pushed me in the right direction towards $rootScope(more info). I added code in app.js which stores the previous state/view name into $rootScope.fromViewThree. I can now access the previous state/view name in the HTML of view 2 and the previous state/view name will be updated when switching state/view has been successful.
Warning:
All scopes inherit from $rootScope, if you have a variable
$rootScope.data and someone forgets that data is already defined
and creates $scope.data in a local scope you will run into problems.
Controller view 2
.controller('ViewTwoCtrl', function($scope, $window) {
$scope.goToViewThree = function() {
$window.location = "#/app/viewthree";
};
})
Controller view 3
.controller('ViewThreeCtrl', function($scope, $window) {
$scope.goToViewTwo = function() {
$window.location = "#/app/viewtwo";
};
})
Directives.js
I no longer need the service because I use $rootScope now to monitor which view is my previous view.
HTML view 2
<div class="row" ng-if="fromViewThree != 'app.viewthree'">
<p>You came from view home!</p>
</div>
<div class='row' ng-if="fromViewThree == 'app.viewthree'">
<p>You came from view three!</p>
</div>
<div class="row">
<button id="activateCameraBtn" class='button' ng-click="goToViewThree()" ng-if="fromViewThree != 'app.viewthree'">Go to view 3</button>
<button id="activateCameraBtn" class='button' ng-click="goToViewThree()" ng-if="fromViewThree == 'app.viewthree'">Go again to view 3</button>
</div>
HTML view 3
The HTML for view 3 hasn't changed.
App.js
angular.module('myApp', [])
.run(function($rootScope) {
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
$rootScope.fromViewThree = from.name; //e.g. app.home
});
})
....
I have a single page app '(Backend in Python/Django)' where my functions return json response and that json response handled by angular js in front end . I am using angular ajax call to hit the function. Now we all know that on ajax call url in address bar do not get changed. But in angular js we can set url using $location.path(). So it keeps the history of url I have visited and on browser back button it changes the url in address bar to previous one . But it do not change the content of the page.
My angular ajax call :
app.controller('myController',
function($scope,$http, $location, $route, $timeout){
$scope.formData={}
$scope.getAllBrainframes=function(id){
if(id){
$scope.url = '/get-brainframe/'+id+'/';
}else{
$scope.url = '/get-brainframe/';
}
$http.post($scope.url)
.success(function(data,status){
.success(function(data,status){
$scope.title = data[0].title
$scope.brainframes = data;
$location.path($scope.url);
$scope.parent= data[0].id;
})
.error(function(data,status){
});
}
});
As I am setting $location.path() on ajax success , so it appends the current visited url in address bar and keeps history of every url i have visited. But when I click on browser back button it changes the url in address bar to previous one but not the content.
Now is there any function that i can trigger when I click on browser back button or how I can change the content of page ?
EDIT :
above ajax success function edited .
My html :
<div class="content">
<span ng-repeat="brainframe in brainframes">
<p ng-if = "brainframe.brainframes.length > 0 ">
<ul class="list-group col-md-5">
<div data-ng-repeat="brain in brainframe.brainframes" class="child-brainframes">
<a class="my-title" ng-click="getAllBrainframes(brain.brainframe_child.pk)">
<li class="list-group-item"><span class="badge">{$ brain.count_children $}</span>{$ brain.brainframe_child.title $}</li>
</a>
</div>
</ul>
</p>
<p ng-if = "brainframe.brainframes.length < 1 ">
<span>No brainframes are available.</span>
</p>
</span>
</div>
You need to look at $routeParams and change the content in the template.
DEMO
.controller("MainCtrl",
function($scope,$http, $location, $route, $timeout, $routeParams){
$scope.formData={};
$scope.id = $routeParams.id;
$scope.getAllBrainframes=function(id){
if(id){
$scope.url = '/home/'+id+'/';
}else{
$scope.url = '/home';
}
console.log($scope.url);
$location.path($scope.url);
};
});
In your template:
Check for the $scope property and show/hide
<script type="text/ng-template" id="Home.html">
<p>This is one template</p>
<p ng-if="id">This is in next template</p>
<a ng-click="getAllBrainframes('1')">next template</a>
</script>
Check full code here
UPDATED:
If you want to persist the ajax call data between routes, you need to probably store it in a service and access it in your controller based on the $routeParams from the service.