AngularJS reloaded controller dont change DOM - javascript

I have an angularJs Application.
In there i have a "LayoutCtrl" (LayoutController) which is saying (for example) "How many head menu links are existing".
I have created my Controller and my Service - it works fine.
Now, in some cases the site needs new HeadMenu-Links (e.g. at login / logout) or widgets (little boxes with extra content at side).
So i getted the $scope from the LayoutCtrl to the controller (for grabbing it later and chaning its values).
At testing (alert some values) my $scope has always the corrent values, also changes in the returned JSON (from php service).
But the DOM dont changes.
What could it be?
The part of Layout:
<div ng-controller="LayoutCtrl">
<div desc='header' class='header' >
<a desc='hp_link' class='hp_link' href="#{{header.index}}">
<img desc='banner' class='banner' ng-src="{{header.banner}}" src="zkLib/f/img/ajax-loader-sm.gif">
</a>
<div desc='headerRow' class='headerRow'>
<div desc='headerMenu' class='headerMenu'>
<span ng-repeat="m in header.mHead">
<span desc='hmLink' class='hmLink' >
<a desc='headerLink' class='headerLink' href="{{m.link}}">{{m.text}}
<img desc='headerImg' class='headerImg' ng-src="ico/{{m.image}}" heightt="16px;"/>
</a>
</span>
</span>
</div>
<div desc='networksMenu' class='networksMenu'>
<span ng-repeat="n in header.network">
<span desc='nwLink' class='nwLink' >
<a desc='networkLinK' class='networkLinK' target="_blank" title="{{n.name}}" href="{{n.link}}">
<img desc='networkImg' class='networkImg' ng-src="zkLib/f/img/icons/{{n.icon}}"/>
</a>
</span>
</span>
</div>
</div>
</div>
</div>
The Controller:
app.controller("LayoutCtrl", ["$scope", "$route",
"HeaderService", "AppService", "WidgetsService", "FooterService",
function($scope, $route, HeaderService, AppService, WidgetsService, FooterService) {
$scope.refresh = function(route) {
HeaderService.query().then(
function(result) { $scope.header = result.data }, function(result) {}
);
WidgetsService.query().then(
function(result) { $scope.widgets = result.data }, function(result) {}
)
$scope.$route = route;
alert(JSON.stringify($scope.header));
};
$scope.refresh($route);
AppService.query().then(
function(result) { $scope.app = result.data }, function(result) {}
);
FooterService.query().then(
function(result) { $scope.footer = result.data }, function(result) {}
);
AppService.$scope = $scope;
}]);
One of the called services:
app.factory('HeaderService', ['$http', '$q',
function ($http, $q) {
var service = {};
service.query = function() {
var data = $http.get(sAddr('header'));
var deffered = $q.defer();
deffered.resolve(data);
return deffered.promise;
};
return service;
}]);
(sAddr returns the corrent server path to service)
On other Controllers (e.g. index page, user page...) i call
AppService.$scope.refresh($route);
to force the controller refresh (new Menus? New Widgets?) and it reload correctly (i think) - the alert in the code above print me out the correct json.
But the DOM dont change.
What i´m doing wrong?
I´ve builded this pattern with this example code from an other StackOverFlow-Question:
enter link description here
I´ve build an similar example with the Servoce.$scope.refresh-Call on other Controller (TestController) - it worked fine... but here - with no differences, not.
Thanks for answers - Kai

You try $scope.$apply() or $rootScope.$digest() to get all of the data refreshed in your DOM. Updating any of the models from outside of the controller it is bound to will update the data but Angular doesn't know about it. Sometimes, setting a watch with $scope.$watch and updating the values inside the controller will give you the refreshed data in the DOM.
Trying a $scope.$digest() at the end of your promises is also an option.
http://nathanleclaire.com/blog/2014/01/31/banging-your-head-against-an-angularjs-issue-try-this/

Related

Dynamic routing depending on servers response in angularjs

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);
}}}])

How to display a returned json in angular view?

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();

Can't get the datas in angularJs

I have html page like
<div ng-controller="userListControl">
...
</div>
<div ng-controller="userDetailsControl">
....
</div>
And i have angular Js code is
var userDirectory = angular.module('userDirectory',[]);
userDirectory.controller("userListControl", ['$scope','$http', function($scope, $http)
{
$http.get('data/userData.json').success (function(data){
$scope.users = data;
$scope.users.doClick = function(user,event) {
userInfo(user);
}
});
}]);
function userInfo(users)
{
console.log(user);
userDirectory.controller("userDetailsControl", function($scope)
{
console.log('well')
$scope.user = users;
console.log($scope.user)
});
}
Here Everything is working fine. But when we are calling click event, That userInfo called with particular Data. But Second controller gives an error(angular js Error).
I am new one in angular jS. I dont know this logic is correct or not.
I have list items in first Controller. When we are clicking on list, It gets data from particular list and passed to another design. That design have detailed data. So the 2nd controller shows particular list detailed Section
First, There is no need to declare your controller inside a function - I don't think that you're trying to lazy-load controllers. Make it available to your app when it starts.
Second, you need to pass data to the userDetailsControl controller. There are various ways to do this, but here you could just use the $rootScope.
var userDirectory = angular.module('userDirectory',[]);
userDirectory.controller("userListControl", function($scope, $rootScope, $http)
{
$scope.selectUser = function(user){
$rootScope.selectedUser = user;
}
$http.get('data/userData.json')
.success (function(data){
$scope.users = data;
});
})
.controller("userDetailsControl", function($scope, $rootScope){
$rootScope.$watch("selectedUser", function(newVal){
$scope.user = newVal;
}
}
and in your HTML:
<div ng-controller="userListControl">
<button ng-repeat="user in users" ng-click="selectUser(user)">{{user.name}}</button>
</div>
<div ng-controller="userDetailsControl">
<div>{{user.name}}</div>
<div>{{user.otherDetails}}</div>
</div>

Pass a variable between controller and use ng-repeat on same page

Some of my wording may be off especially regarding angular/js terminology (controller, service, factory, etc), but hopefully it is still understandable. Also, this question has multiple parts, which made it difficult to ask in one line.
I have 3 files: newRegistration.html, Registration.js, and addressVerification.js.
In newRegistration.html, there is a form where the user inputs his/her email, phone, mailing address, and other things and then clicks "next". Upon clicking next, Registration.js (a controller?) is triggered (?).
newRegistration.html
In the following snippet is the ng-repeat that I'd like to update with new data from addressVerification.js.
<div id="dialog-form" title="CHOOSE THE CORRECT ADDRESS">
<ul>
<li ng-repeat="for item in [not sure what to put here because of two js files]">
</li>
</ul>
</div>
Registration.js
The controller for the template that contains the ng-repeat mentioned above.
The top line looks like this:
angular.module('appname')
.controller('RegistrationCtrl', function ($scope, $http, cacheStore, countryStates, birthYear, $anchorScroll, errorMessages, addressVerification, UtilsFactory)
And this is a line that may be relevant:
addressVerification.verify(user).then(function (userObj)
addressVerification.js
Uses the Smartystreets API to correct/suggest the mailing address.
I can't figure out how to pass variables from this module to Registration.js (where the scope variable [?] is) in order to populate the ng-repeat in newRegistration.html.
angular.module('appname').factory('addressVerification', function($q, userIdentity, $http, smartyToken) {
"use strict";
return {
verify: function(obj) {
var deferred = $q.defer(),
street2QS = "";
if (obj.address2 || obj.address2 !== "") {
street2QS = "&street2=" + encodeURIComponent(obj.address2);
}
$http.jsonp("https://api.smartystreets.com/street-address?street=" + encodeURIComponent(obj.address1)
+ street2QS
+ "&city=" + encodeURIComponent(obj.city)
+ "&state=" + encodeURIComponent(obj.state)
+ "&zipcode=" + encodeURIComponent(obj.zip)
+ "&source=website&auth-token="+ smartyToken.get() + "&candidates=5&callback=JSON_CALLBACK")
.success(function (response) {
var metaData,
components;
if (response && response.length === 1) {
metaData = response[0].metadata || {};
components = response[0].components || {};
angular.extend(obj, {
"address1": [
components.primary_number,
components.street_name,
components.street_suffix
].join(" "),
"address2": [
components.secondary_designator,
components.secondary_number
].join(" "),
"city": components.city_name,
"county_name": metaData.county_name,
"county_fips": metaData.county_fips,
"state": components.state_abbreviation,
"latitude": metaData.latitude,
"longitude": metaData.longitude,
"plus4_code": components.plus4_code,
"zip": components.zipcode
});
deferred.resolve(obj);
} else {
deferred.reject(false);
}
}).error( function() {
deferred.reject(false);
});
return deferred.promise;
}
};
});
I'm pretty clueless right now. I think I've given all of the necessary details. I wish I knew where to start. I read all about deferred objects, ng-repeat, and controllers, but it's confusing me.
Any help appreciated.
You're injecting addressVerification into RegistrationCtrl. The value of addressVerification that is injected into the RegistrationCtrl is the value returned by executing the function you're defining here:
angular.module('appname')
.factory('addressVerification', function($q, userIdentity, $http, smartyToken)
Therefore you can access the stuff that's happening inside of the addressVerification.js file in the RegistrationCtrl.js file by adding methods to whatever it is you're returning in that function.
Once you have your data in RegistrationCtrl, you can access it from the view by appending data to the scope inside of RegistrationCtrl. Example:
This would go in RegistrationCtrl.js:
$scope.someItems = [1, 2, 3, 4];
This would go in the view:
<li ng-repeat="item in someItems">{{item}}</li>
The way that I have implemented this is by exposing methods of a factory that allow the controllers (and the controller's view(s)) that depend on it to store values within the same factory.
For example, in the following code, the setCurrent method of the customers factory stores a value, current in the factory. Because factories are singletons, will persist in the application. Even after the user's click on the <a> (in the following example) and they are taken to href="/", the value that was stored in customers.current will be accessible to the "/" route's controller if the same factory is a dependency for both controllers.
Template
<ul>
<li>{{customers.current.name}}</li>
<li
ng-repeat="customer in customers.all"
>
<a
class="action name"
ng-click="customers.setCurrent(customer)"
href="/"
>
{{customer.name}}
</a>
</li>
</ul>
Controller
angular
.module('CtrlCustomerList', [
'CollectionCustomers',
])
.controller('CtrlCustomerList', function($scope, CollectionCustomers) {
$scope.customers = CollectionCustomers;
});
Factory
angular
.module('CollectionCustomers', [
])
.factory("CollectionCustomers", function(Restangular, ModelCustomer, $location) {
return {
all : [],
current : null,
setCurrent : function() {
// Affect this.current
}
}
});

Triggering function on ngclick with AngularJS

I have a function that makes a $http call to an external API and then populates some results within an ng-repeat array.
Right now the function gets triggered on every element on the ng-repeat, which creates a whole lot of server calls. I'd like for the function to only make the call once an element from the ng-repeat is clicked upon.
I've tried with ng-click, but i'd say i'm missing something.
The $http query that i'm trying to call on click is the second one:
function ImageCtrl($scope, $http) {
$scope.image = 'img/record-default.png';
$http.get('http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=e8aefa857fc74255570c1ee62b01cdba&artist=' + $scope.artist.name + '&album=' + $scope.release.title + '&format=json').
success(function (data4) {
$scope.image = data4.album.image[2]['#text'];
}
)
function getVersions ($scope, $http){
$http.get('http://api.discogs.com/masters/' + $scope.release.id + '/versions').
success(function (data5) {
$scope.versions = data5.versions;
});
}
}
And the relevant html:
<div class="col-md-3" ng-controller="ImageCtrl" ng-repeat="release in releases | filter:album | filter:year | filter:{ role: \'main\' }" >
<div class="release" ng-click="getVersions()"> \
<img class="img-responsive" ng-src="{{image}}" /> {{release.title}}
<ul ng-controller="ImageCtrl">
<li ng-repeat="version in versions">{{version.format}}</li>
</ul>
</div>
</div>
And a working Plunker. Function in question is line 60 on script.js
So I ended up taking what you have shown and doing some refactoring.
I moved getVersions to the prototype, and use it to append versions to a release object instead of the $scope.
function ImageCtrl($scope, fakeService) {
var _this = this;
this.fakeService = fakeService;
this.$scope = $scope;
fakeService.getReleases()
.then(function (releases) {
$scope.releases = releases;
});
this.$scope.getVersions = function(release){
_this.getVersions(release);
};
}
ImageCtrl.$inject = ['$scope', 'fakeService'];
ImageCtrl.prototype.getVersions = function (release) {
this.fakeService.getVersions(release.id)
.then(function (versions) {
release.versions = versions;
});
};
The markup isn't terribly different, but you can see where I pass the actual release object into the getVersions function in the click event. This way it always acts directly on the object bound to that particular row.
<div class="row" ng-controller="ImageCtrl">
<div class="col-md-3" ng-repeat="release in releases">
<div class="release" ng-click="getVersions(release)">
<h1>{{release.title}}</h1>
<img class="img-responsive" height="100" width="100" ng-src="{{release.image}}" />
<ul>
<li ng-repeat="version in release.versions">{{version.format}}</li>
</ul>
</div>
</div>
</div>
And here is a working demo showing the whole thing in action: http://jsfiddle.net/jwcarroll/k6mkt/
I'm using a fake service here to mimic calling a web service in order to get the data. I highly recommend wrapping up your calls to $http in order to encapsulate data access in your controller.

Categories

Resources