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.
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 am implementing a search in the github repository.
I need to display the information that i get from here: https://api.github.com/search/repositories?q=bootstrap . for instance into a view or HTML
<div ng-app="newsearchApp">
<div ng-controller="MainCtrl">
<form action="#/about" method="get">
<input ng-model="searchText" />
<button ng-click="search()">Search</button>
</form>
</div>
</div>
the code for searching the Github repository;
angular.module('newsearchApp')
.controller("MainCtrl", ["$scope", function($scope) {
$scope.searchText = "";
$scope.search = function() {
console.log($scope.searchText);
var item = $scope.searchText;
// console.log(item)
var GithubSearcher = require('github-search-api');
var github = new GithubSearcher({username: 'test#something.com', password: 'passwordHere'});
var params = {
'term': $scope.searchText
};
//i am not certain about the 'userData'
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data; //i am not certain about the 'repoData'
});
} }]);
the problem is here, when populating the json object to HTML
<div ng-repeat="repo in userData | filter:searchText | orderBy:predicate:reverse" class="list-group-item ">
<div class="row">
<div class="col-md-8">
<h4>
<small>
<span ng-if="repo.fork" class="octicon octicon-repo-forked"></span>
<span ng-if="!repo.fork" class="octicon octicon-repo"></span>
<small>{{repo.forks_count}}</small>
</small>
<a href="{{repo.html_url}}" target="_blank" >
{{repo.name}}
</a>
<small>{{repo.description}}</small>
<small>{{repo.stargazers_count}}</small>
<a href="{{repo.open_issues_count}}" target="_blank" >
Open Issues
</a>
<small>{{}}</small>
</h4>
</div>
</div>
</div>
the results are null on the HTML but are not null on the console.
thanks in advance
the results are null
The problem is, that Angular doesn't notice that the GitHub server has answered and doesn't update the view. You have to tell Angular manually to re-render the view. Try calling $scope.$apply():
github.searchRepos(params, function(data) {
console.log(data);
$scope.userData = data;
$scope.$apply();
});
If you'd make your request to the GitHub API with Angulars $http service, then this would not be needed - you'll only need $scope.$apply() if something asynchronous happens which doesnt live in the "Angular world" - for example things like setTimeout, jQuery ajax calls, and so on. That's why there are Angular wrappers like $timeout and $http.
More details: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html
The GitHub API can be accessed using the AngularJS $http service:
app.controller("myVm", function($scope,$http) {
var vm = $scope;
var url = "https://api.github.com/search/repositories?q=bootstrap"
$http.get(url).then(function onSuccess(response) {
vm.data = response.data;
console.log(vm.data);
})
})
HTML
<div ng-app="myApp" ng-controller="myVm">
<div ng-repeat="item in data.items">
{{item.full_name}}
</div>
</div>
The DEMO on JSFiddle
Since you're not using the Angular $http service, angular is not aware of the changes. You need to manually tell Angular to re-render and evaluate by using
$scope.$apply();
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.
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 two ajax calls. The data starts from the html (input), when enter is pressed, what is in the input field is sent to the controller then to the factory which makes the first ajax call. The success is handled back in the controller, then another ajax call is requested, and the data from that request is handled back in the controller again. I have a $scope -- $scope.ytChannel = data.items; in that final success within the function that does not seem to be working. Here is my code starting with the html
HTML:
<input class="form-control channel-index" type="text" ng-model="channel" placeholder="Enter Channel" ng-keydown="$event.which === 13 && cname(channel)"/>
JS:
.factory('ytVids', function($http){
return{
getChannel: function(name){
var url = 'https://www.googleapis.com/youtube/v3/channels? part=contentDetails&forUsername='+ name +'&key=[my api key]';
return $http.get(url);
},
getVids: function(channel){
return $http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet%2CcontentDetails&maxResults=50&playlistId='+channel+'&key=[my api key]');
}
};
})
.controller('MainCtrl', function ($scope, ytVids) {
$scope.cname = function(channel){
ytVids.getChannel(channel).success(function(response){
//console.log(response);
console.log(response.items[0].contentDetails.relatedPlaylists.uploads);
ytVids.getVids(response.items[0].contentDetails.relatedPlaylists.uploads)
.success(function(data){
console.log('in success');
console.log(data.items);
$scope.ytChannel = data.items; // This is the scope that is not seeming to want to work.
});
});
};
});
And here is the html that calls that ytChannel
<ul>
<li ng-repeat="item in ytChannel" class="col-xs-12 col-sm-6 col-md-4 vid-options">
<a href="#">
<div class="title">{{item.snippet.title}}</div>
<img src="{{item.snippet.thumbnails.maxres.url}}" />
</a>
</li>
</ul>
if a scope is in a function, does the html not have access to it? What can be done so I can have access to the returned data?
Error
This is the error the console gives in the dev tools GET http://localhost:9000/%7B%7Bitem.snippet.thumbnails.maxres.url%7D%7D 404 (Not Found)
The correct code is
<img ng-src="{{item.snippet.thumbnails.maxres.url}}" />
As the manual says,
Using Angular markup like {{hash}} in a src attribute doesn't work
right: The browser will fetch from the URL with the literal text
{{hash}} until Angular replaces the expression inside {{hash}}. The
ngSrc directive solves this problem.