I have a classic scenario: filters on the left side, list of products on the right. User clicks on a filter, list of products refreshes.
I'm using 2 partial views, both views share the same controller.
<div class="row">
<div ng-include="'/views/filters.html'"></div>
<div ng-include="'/views/products.html'"></div>
</div>
The controller makes calls to a nodejs backend that talks to elasticsearch.
.controller('AppCtrl', ['$scope', '$http', '$timeout', function($scope, $http, $timeout){
$http.get('/getAll')
.success(function(data) {
$scope.products = data.hits.hits;
})
.error(function(data) {
console.log('Error: ' + data);
});
$scope.filterClick = function($event, filterClicked) {
$http.get('/getSingleFilter', {
params: {
filter: filterClicked
}
})
.success(function(data) {
$timeout(function(){
$scope.products = data;
console.log($scope.products);
});
})
.error(function(data) {
console.log('Error: ' + data);
});
}
}]);
The call to getAll works fine, products.html displays all products.
getSingleFilter doesn't refresh the list though. I do see the correct list printed in the console, but the view doesn't refresh.
What am I missing?
Any specific reason why you are using $timeout? Judging by the code you provided, you dont need to use it. $digest cycle will be triggered by $http, and your model should be successfully updated as with your $http.get('/getAll') example
.success(function(data) {
$scope.products = data;
})
Ok, I found the problem. I put the 2 partials in the same partial, and put the code inside a
<div ng-controller='AppCtrl'>
and it worked.
Before I had the ng-controller='AppCtrl' directive show up in both partials and I think that was the issue. I may just leave it like this now, or create 2 controllers and then have a service to share the data.
Related
My English is very bad,at first Controller,I post data form The server,and i got a $rootScope.YD for Transfer data .but when i use the YD in the second page,it does't work.can you help me ?
.controller('yd_homeCtrl',function($rootScope, $scope, $state, $http,$ionicActionSheet, $ionicModal)
{
$scope.getReadList = function ()
{
var url = $rootScope.rootUrl + "/read.php";
var data = {
"func":"getReadList",
"unionid":$rootScope.userinfo.unionid,
"fr":1
};
encode(data);
$rootScope.LoadingShow;
$http.post(url, data).success(function (response)
{
$rootScope.LoadingHide();
$rootScope.YD=response.data.result[0];
$state.go('yd_improve')
}).error(function (response, status)
{
$rootScope.LoadingHide();
$rootScope.Alert('连接失败![' + response + status + ']');
return;
});
}
})
.controller("yd_improveCtrl",function($rootScope, $scope, $state, $http, $ionicActionSheet, $ionicModal, $stateParams, $interval, $sce, $ionicHistory,$ionicSlideBoxDelegate)
{
$scope.text="";
angular.forEach($rootScope.YD,function(value,key){
if(key==0)
{
//alert(1111111);
//alert(value.text);
$scope.text=value.text;
alert($scope.text);
}
});
});
there is app.js state:
.state('yd_improve', {
cache: false,
url: '/yd_improve/:id',
onExit: function ()
{
var v = document.getElementById("audio");
v.pause();
v.src = "";
},
templateUrl: 'templates/yd_improve.html',
controller: 'yd_improveCtrl'
})
Use $broadcast service. It's the most reliable solution for broadcasting events and passing parameters between controllers.
Don't rely on storing data in service because on page refresh, service also gets refreshed and you will lose the data stored in service's variable. So maintaining state in service is highly unrecommended. Use $broadcast instead.
You have a couple of options. Create a service which stores the information. In first controller set the data. And in second controller get the data.
Or you can use $broadcast. This publishes an event with a name you give it and the data you parse through. You do this on first controller. And on second controller listen for the event using $rootScope.on.
But I'd recommend using a service its best solution in terms of memory and performance.
I have an issue when I try to display data.
I send my form and update my database (it works great, backend is ok)
I use a button on the page to return to homepage
The view of the homepage is not updated, always the same values.
(It seems that there is only the template that loads, not with queries)
I need to click on the button refresh of the browser to see new values.
After the 'hard' refresh, the view is updated.
Why do I need to completely refresh the page ?
Here is my code
JS :
My service GenericService
(I created this service because I use this in several controllers)
myApp.factory('GenericService', function ($http, $q, MyFunctions) {
var data = {};
function getDataIfNeeded(action) {
action = action || 'default';
if (data[action] !== undefined) {
return $q.when(data[action]);
}
return $http({
url: "php/functions.php",
method: "GET",
params: {
action: action,
dummy: MyFunctions.randomString(7)
}
}).then(function(response) {
data[action] = response.data;
return data[action];
});
}
return {
getData: getDataIfNeeded
};
});
The call of the service
myApp.controller('listCtrl', ['$scope', '$http', '$rootScope', '$location', 'GenericService',
function ($scope, $http, $rootScope, $location, GenericService) {
GenericService.getData("get_projects").then(function (data) {
$scope.projects = data;
});
GenericService.getData("get_projects_draft").then(function (data) {
$scope.projects_in_draft = data;
});
}]);
HTML :
<div ng-controller="listCtrl">
<div ng-repeat="project in projects">
<span>{{ project.nom }}</span>
</div>
<div ng-repeat="project_draft in projects_in_draft">
<span>{{ project_draft.nom }}</span>
</div>
</div>
Your service GenericService fetch the data from the server only "if needed", which means if the local data variable isn't empty. Naturally, without reloading the service and after a form submission, the data will be out-of-sync! So you have two choices:
If the server is creating additional data, i.e. possesses data that AngularJS don't have after the form submission, you need to do another request in order to fetch the new data. Just empty the local data variable.
Else, if the server is just saving the data in a database for instance, and doesn't perform any other operation with an impact on what is shown on your page, you don't have to do an other request, since you already know what you sent to the server! Just update the local data variable.
First off, i found the api address from this topic:
Laravel 4 and Angular JS and Twitter Bootstrap 3 Pagination
Now i am working about this, my little script is so:
var app = angular.module('kategori', [
'ngResource',
'apiBaseRoute'
]);
app.factory('Data', ['$resource', 'apiBaseRoute', function($resource, config){
return $resource('http://develop.alexei.me/careers/careers.php?callback=JSON_CALLBACK&page=:page', {
page: 1
}, {
'get': {
method: 'JSONP'
}
});
}]);
app.controller('KategoriListCtrl', function($scope, Data){
$scope.init = function() {
Data.get({}, function(response){
$scope.kategoriList = response.careers;
},function(error){
console.log("HATA VAR" + error);
});
};
});
app.directive('paginate', function(){
return{
scope:{ allData: '=paginate2' },
link: function(scope){
console.log(scope);
}
}
});
And this is the html side :
<div class="col-md-6 col-md-offset-3" ng-controller="KategoriListCtrl" ng-init="init()">
{{kategoriList}}
<div paginate paginate2="kategoriList"></div>
</div>
as you see, console.log(scope) inside directive is shows a lot of things in console, especially i see allData there with lots data, but if i change it to
console.log(scope.allData)
it prints undefined..
i don't understand why. how can i solve this? thanks.
By the time JS reaches your console.log the allData property is undefined (since kategoriList is undefined). kategoriList (and thus allData) is created (and populated with lots of data) asynchronously at a later time.
So, why do you see the data when logging the scope object instead ?
At the time the object is logged it has no property allData (and no data).
But by the time you go over to the console and expand the node and look for the allData property, the property has been added and populated by your AJAX call (using $resource).
It is not clear what you want to do with allData.
If you want to use it in e.g. ng-repeat you don't have to worry: You can use it normally (as if it were defined) and Angular will automatically "pick it up" as soon as it arrives and do stuff.
Yet, if you want (for your own mysterious reasons) to get informed when it is ready, your can use $watch:
scope.$watch('allData', function(newValue) {
if (newValue !== undefined) {
console.log(scope.allData);
}
});
See, also, this short demo.
I am using Angular-JS with .net web api.
the program will display list of "Profiles", and when a user click on any it will navigate to the details.
The list part works fine, but the details doesn't display any data
the code is as follows:
var profileModule = angular.module('profileModule', ['ngResource', 'ngRoute']);
profileModule.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/profile', {
controller: 'profileController',
templateUrl: 'Partials/profileList.html'
})
.when('/profile/:profileId', {
templateUrl: 'Partials/profileDetail.html',
controller: 'profileDetailController'
})
.otherwise({ redirectTo: '/profile' });
}]);
profileModule.controller('profileController', function($scope, profileFactory) {
$scope.profiles = [];
function init() {
$scope.profiles = profileFactory.query();
}
init();
});
profileModule.controller('profileDetailController', function ($scope, $routeParams, profileFactory) {
$scope.profile = {};
function init() {
$scope.profile = profileFactory.get({ Id: $routeParams.profileId });
}
init();
});
profileModule.service('profileFactory', function ($resource) {
return $resource("api/profiles/:Id");
});
and the detailed page profileDetail.html looks like this
<div>
<h2>profile Details</h2>
<p>
Name: <br/>
{{profile.Name}}
</p>
{{doit}}
</div>
the list page profileList.html looks like this
<div class="container">
<h1>Profiles by sort order</h1>
<span data-ng-repeat="profile in profiles | orderBy: 'Sequence'">
<a data-ng-href="#/profile/{{profile.Id}}">
{{profile.Name}}
</a><br/>
</span>
</div>
The list part works fine, and when I click on the link, I can see the rest call to the web api as follows
/profiles/4
and I can see the JSON that is returning back
but no binding at all is happening on the detail page
get() function of $resource service can be used when your GET request to the resource returns just one object. Check your browser's developer tools, you might see an error in the console saying: "Error in resource configuration. Expected response to contain an object but got an array".
To make your code work, modify your init() function to use query instead of get:
function init() {
$scope.profile = profileFactory.query({ Id: $routeParams.profileId });
}
As far as I know, this should resolve your issue. If it doesn't, put a comment here.
I'm new to angularjs and have been attempting to use the angularui modules to build an accordion. For each accordion header I have a nested tag to which calls my service factory. The service factory returns data according to the id and updates my inner accordion content however it updates it for all of the accordion headers. So in other words, clicking on an accordion header will load the same content for all accordion divs. I would like it to return only to the clicked header. I believe I need more help in understanding the scope of my factory service. So my question is if someone can help me understand how to get my service factory to only update it's caller.
my html:
<accordion close-others="false">
<accordion-group ng-repeat="dept in departments">
<accordion-heading>
<span ng-controller="DeptHeaderCtrl" ng-click="loadEmps(dept.DeptID)">
{{dept.DepartmentName}} ({{dept.DepartmentShortName}})
</span>
</accordion-heading>
<div ng-controller="departmentList">
<div ng-repeat="emp in deptemps">
{{emp.Name_First}}
</div>
</div>
</accordion-group>
angularjs factory service code:
app.factory('DeptFactory', function ($http, $rootScope) {
var sharedDeptEmpList = {};
sharedDeptEmpList.EmpList = '';
sharedDeptEmpList.fetchDeptEmps = function (deptid) {
var dept = { "userid": userid, "deptid": deptid };
$http({ method: 'POST', url: 'api/Fetch/DeptEmployees/', data: dept }).
success(function (data, status, headers, config) {
EmpList = data;
sharedDeptEmpList.broadCastEmpList();
}).
error(function (data, status, headers, config) {
alert('error');
});
};
sharedDeptEmpList.broadCastEmpList = function () {
alert('broadcasting');
$rootScope.$broadcast('handleBroadcast');
};
return sharedDeptEmpList;
});
Angularjs controller that receives broadcast:
app.controller('departmentList', function ($scope, $http, DeptFactory) {
$scope.init = function (p_userid) {
userid = p_userid;
};
$scope.$on('handleBroadcast', function () {
alert('broadcast received');
$scope.deptemps = EmpList;
});
});
Each directive is just some javascript that associates a DOM node with a given scope. The same way you think of the DOM tree, you can think of a "scope tree". On the other hand, services are just singleton objects that can be injected and used anywhere. They have no implicit relationship to the DOM/scope tree.
By injecting $rootScope into your DeptFactory, you are giving it access to the entire scope tree. When you call $broadcast(), you are sending an event throughout the entire tree, beginning at the root, and then propagating outwards to all of the leaf scopes.
I don't see enough of your code to completely understand what's happening, but I'm guessing that you're seeing all of your accordion divs change because they are all receiving your $broadcasted event, and reacting to it the same way. I would suggest you $broadcast some sort of ID value to identify which div you are trying to change. Then, when you handle this event in each accordion, check the ID against the accordion's ID to see it should change or not.
Does this help?