I have looked at a number of other questions related to this such as
AngularJS : ng-repeat list is not updated when a model element is spliced from the model array
ng-repeat not updating on update of array
However I think that the way I built my app is sufficiently different that these aren't helping me.
I think my idea of doing this:
$rootScope.$on('connectionDispositionChanged',function(event, item){
$scope.data.matches[item.index].info.disposition = item.disposition;
});
Isn't really working out the way I had hoped. I can actually see in the console that this updating, but it doesn't update in the table. Adding $scope.$apply() after this causes a digest in-progress error.
show.phtml
<div class="container-fluid" ng-app="analysisApp" ng-controller="analysisController">
<table class="table table-condensed">
<thead>
<tr >
<th ng-repeat="header in baseColumns" class="text-center">{{header.name | tableHeader}}</th>
<th ng-repeat="header in comparisonColumns" class="text-center text-info">{{header.name | tableHeader}}</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr table-row data="data" ng-repeat="item in data.matches | filter:searchMatchText track by $index">
</tbody>
</table>
<row class="col-md-12 text-center"><span class="text-muted">End of Data</span></row>
</div><!-- #matches -->
</div>
tableRowDirective.js
"use strict";
analysisApp.directive("tableRow", function($compile) {
var getTemplate = function(scope, element, attrs){
var base = scope.item.base;
var comp = scope.item.comparison;
var info = scope.item.info;
// other non-relevant code...
returnString += '<td class="text-center"><button class="btn btn-default btn-xs" ng-click="matchesSetDisposition(item, data.settings, $index)" >Set Disposition</button>';
returnString += '</td>';
return returnString;
};
var linker = function(scope, element, attrs){
element.html(getTemplate(scope, element, attrs));
$compile(element.contents())(scope);
};
return {
restrict : "A",
replace : true,
link: linker
};
});
analysisController.js
"use strict";
analysisApp.controller('analysisController', ['$scope','$rootScope','loadData','saveData','$uibModal', function ($scope, $rootScope, loadData, saveData, $uibModal, $log) {
$rootScope.$on('connectionDispositionChanged',function(event, item){
// $scope.data.matches[item.index].info.disposition = item.disposition;
});
$scope.matchesSetDisposition = function(item, scope, index){
var modalInstance = $uibModal.open({
animation: $scope.animationsEnabled,
templateUrl: '/angular/analysis/templates/matches-modal.html',
controller: 'matchesModalController',
size: 'lg',
resolve: {
itemData: function () {
return {
dispositionLabels: $scope.dispositionLabels,
disposition: item.info.disposition,
connectionID: item.info.id,
comparisonID: comparisonID,
baseItemID: item.base.id,
baseTitle: itemTitle(item.base),
comparisonItemID: item.comparison.id,
comparisonTitle: itemTitle(item.comparison),
index: index
}
}
}
});
modalInstance.result.then(function (item) {
$scope.data.matches[item.index].info.disposition = item.disposition;
saveTheData('/analysis/apisaveconnectiondisposition', item);
}, function () {
});
};
}]);
matchesModalController.js
"use strict";
analysisApp.controller('matchesModalController', function ($scope, $rootScope, $uibModalInstance, itemData, saveData) {
$scope.itemData = itemData;
$scope.ok = function (item) {
$uibModalInstance.close(item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
$scope.delink = function (item) {
BootstrapDialog.confirm({
title: 'WARNING',
message: '<p>Are you sure that you want to break the link between these items?</p>',
type: BootstrapDialog.TYPE_DANGER,
btnOKLabel: 'Break the link',
btnOKClass: 'btn-danger',
callback: function(result) {
if(result) {
$uibModalInstance.dismiss('delink');
saveTheData('/analysis/apidelink', item);
}else {
// cancel the operation
}
}
});
};
var saveTheData = function(url, item){
saveData
.postData(url, item)
.then(function(dataResponse){
$rootScope.$broadcast('connectionDispositionChanged', item);
})
};
});
Related
I want to send the limit and offset values from client side(angularjs) to nodejs.so
i tried with static values.
my html code :
<div class="prprt-list-ctr row" id="viewpage">
<div class="hmpal-prprt-wdgt clearfix" ng-repeat="project in properties" scroll-trigger="loadMoreRecords()">
<div class="hmpal-prprt-img">
</div>
</div>
</div>
In this properties(ng-repeat) variable is over lapping when i scroll the page ends . This loadMoreRecords() functions when the page scrolls to end.
my directive is scroll-trigger
sidemenu.directive('scrollTrigger', function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
angular.element(document).bind('scroll', function() {
if (jQuery(document).height() <= jQuery(window).scrollTop() +jQuery(window).height()) {
scope.$apply(attrs.scrollTrigger);
}
});
}
};
});
my controller code:
sidemenu.controller('buildersCtrl', ['$scope', '$rootScope', '$location', '$http', 'allServices','$document','PropertyDetails','$routeParams','$window','typeServices', function (a, b, c, d, e,f,h,r,w,t) {
var paging={start:0,rows:15}
e.projectListing(r,paging).then(function (result) {
a.properties = result.data.items;
b.closeid = r.id;
}, function (error) {
});
a.loadMoreRecords = function() {
paging={start:15,rows:30}
e.projectListing(r,paging).then(function (result) {
a.properties = result.data.items;
b.closeid = r.id;
}, function (error) {
});
}
});
I'm currently learning new MVC 6 and stucked completely with simple action - table data update on item selection change.The desired behaviour is to load questions that belong selected question block
I have angularJS factory:
(function () {
'use strict';
angular
.module('questionBlockApp')
.factory('questionBlockService', questionBlockService);
var questionBlockService = angular.module('questionBlockService', ['ngResource']);
questionBlockService.factory('Blocks', ['$resource',
function ($resource) {
return $resource('/api/blocks/', {}, {
query: { method: 'GET', params: {}, isArray: true }
});
}]);
questionBlockService.factory('Questions', ['$resource',
function ($resource) {
return $resource('/api/blocks/:blockId', {blockId : '#blockId'}, {
query: { method: 'GET', params: {}, isArray: true }
});
}]);
})();
Controller, which has refresh func (loadQuestions) built inside selection change function:
(function () {
'use strict';
angular
.module('questionBlockApp')
.controller('questionBlockController', questionBlockController);
//.controller('questionController', questionController);
questionBlockController.$inject = ['$scope', 'Blocks', 'Questions'];
//questionController.$inject = ['$scope', 'Questions'];
function questionBlockController($scope, Blocks, Questions) {
$scope.selectedBlock = 2;
if ($scope.Blocks == undefined | $scope.Blocks == null) {
$scope.Blocks = Blocks.query();
}
$scope.setSelected = function (blockId) {
$scope.selectedBlock = blockId;
$scope.loadQuestions();
}
$scope.loadQuestions = function () {
$scope.data = Questions.query({ blockId: $scope.selectedBlock });
$scope.data.$promise.then(function (data) {
$scope.Questions = data;
});
};
$scope.loadQuestions();
}
})();
And views:
View from which setSelected is called:
<table class="table table-striped table-condensed" ng-cloak ng-controller="questionBlockController">
<thead>
...
</thead>
<tbody>
<tr ng-repeat="block in Blocks" ng-click="setSelected(block.Id)" ng-class="{'selected': block.Id == selectedBlock}">
<td>{{block.Id}}</td>
<td>{{block.Name}}</td>
<td>{{block.Created}}</td>
</tr>
</tbody>
</table>
<table id="test" ng-controller="questionBlockController">
<thead>
<tr>
...
</tr>
</thead>
<tbody>
<tr ng-repeat="question in Questions">
<td>{{question.Id}}</td>
<td>{{question.Text}}</td>
<td>{{question.TimeLimit}}</td>
<td>{{question.Updated}}</td>
</tr>
</tbody>
</table>
When I click on different items in QuestionBlock table, $scope.Questions is updated properly, but the table does not reflect changes, as if no binding exists.
Okay, I am just a bit damaged.
There are two questionBlockController controllers defined, leading to intialization of different scopes => two $scope.Questions objects existence => refresh occured in Blocks scope, which was undesired behaviour.
I have been dealing with this problem for a while. Suppose I have the following directive and controller:
angular.module('LiveAPP.artist',[])
.controller('artistCtrl', ['$scope', '$http', '$location', 'dataFactory', '$routeParams', artistCtrl])
.directive("ratestar", function() {
return {
restrict: "E",
template: "<div id='rateYo'></div>",
link: function( scope, ele, attrs ) {
console.log(scope.ratingInfo)
if(scope.reviews === undefined){
$rateYoMain = $(ele).rateYo({
rating:3
})
} else {
var $rateYo = $(ele).rateYo({
starWidth: "20px",
rating:scope.review.number_of_stars
});
}
}
};
})
function artistCtrl($scope, $http, $location, dataFactory, $routeParams){
$scope.artistName = $routeParams.artistname;
$scope.$watch( 'artistName', function( newValue, oldValue ) {
dataFactory.checkDb( newValue ).then(function(dbData){
if(dbData.data != "No data"){
$scope.artistInfo = dbData.data[0];
$scope.reviews = dbData.data[1];
$scope.ratingInfo = dataFactory.avgReview($scope.reviews);
} else{
dataFactory.artistInfoAPIs(newValue);
}
})
});
$scope.$on('artist:updated', function(event, data){
$scope.artistInfo = data;
});
$scope.ratingInfo = "12";
$scope.artistInfo = {
artist_name: dataFactory.artistInfo.artist_name,
artist_genre: dataFactory.artistInfo.artist_genre,
artist_imageurl: dataFactory.artistInfo.artist_imageurl,
artist_bio: dataFactory.artistInfo.artist_bio
};
}
The associated view is the following:
<div class="mainstar"><ratestar></ratestar></div>
<div class='reviews' ng-repeat="review in reviews">
<ratestar class="reviewstars"></ratestar>
</div>
I having an issue with the scope in the link function. When artistName changes there is a GET request that is sent to the database, which then responds with the correct data. The data that I am concerned about is what gets assigned to $scope.ratingInfo in the promise callback. The weird thing is that this data is 12 when I console.log(scope.ratingInfo) in the link function only for <div class="mainstar"><ratestar></ratestar></div> but not for the <ratestar></ratestar> s in the ng-repeat. Getting '12' makes sense since that is how I define it when the controller is instantiated. Ideally I would like to see the data in the same way that I am seeing it when it comes to <ratestar></ratestar> s in the ng-repeat. I can't seem to figure this out. Anyone have any idea whats going on here?
Could you try this ?
<div class="mainstar"><ratestar ratingInfo="ratingInfo" review="review"></ratestar></div>
<div class='reviews' ng-repeat="review in reviews">
<ratestar class="reviewstars" ratingInfo="ratingInfo" review="review"></ratestar>
</div>
.directive("ratestar", function() {
return {
restrict: "E",
template: "<div id='rateYo'></div>",
scope: {
ratingInfo : '=ratingInfo',
review: '=review'
},
link: function( scope, ele, attrs ) {
console.log(scope.ratingInfo)
if(scope.reviews === undefined){
$rateYoMain = $(ele).rateYo({
rating:3
})
} else {
var $rateYo = $(ele).rateYo({
starWidth: "20px",
rating:scope.review.number_of_stars
});
}
}
};
});
I need to use ng-repeat with ng-bind to display data into a table but what I have tried doesn't display any data,where am I going wrong with the code that I tried?
HTML:
<tbody id="ngDowntimeBody">
<tr ng-repeat="previousdowntime in GetPreviousDowntimeEvents.PreviousDowntimeEvents">
<td ng-bind="previousdowntime.CategoryId"></td>
<td ng-bind="previousdowntime.StartTime"></td>
<td ng-bind="previousdowntime.EndTime"></td>
<td ng-bind="previousdowntime.Comment"></td>
</tr>
</tbody>
JS:
function GetPreviousDowntimeEvents($http) {
var self = this;
self.PreviousDowntimeEvents = [];
self.AjaxData = ngHesto.Ajax.Get($http
, {
url: PREVIOUS_DOWNTIME_EVENTS
, success: function (data) {
self.PreviousDowntimeEvents = data.data[0];
console.log(self.PreviousDowntimeEvents);
}
});
}
var ngAppModule = angular.module('myApp', []);
ngAppModule.controller('DowntimeController', ['$scope','$http', function ($scope, $http) {
$scope.GetPreviousDowntimeEvents = new GetPreviousDowntimeEvents($http);
}]);
The Data doesn't get displayed
This is the response I get back:
{EventId: "10", DepartmentId: "7", CategoryId: "10", StartTime: "2014-08-19T10:00:00", EndTime: "2014-08-19T10:10:00",Comment:"Test"}
JS
function GetPreviousDowntimeEvents($http) {
var self = this;
self.PreviousDowntimeEvents = [];
self.AjaxData = ngHesto.Ajax.Get($http
, {
url: PREVIOUS_DOWNTIME_EVENTS
, success: function (data) {
self.PreviousDowntimeEvents = data.data;
console.log(self.PreviousDowntimeEvents);
}
});
}
var ngAppModule = angular.module('myApp', []);
ngAppModule.controller('DowntimeController', ['$scope','$http', function ($scope, $http) {
$scope.GetPreviousDowntimeEvents = new GetPreviousDowntimeEvents($http);
}]);
HTML
<tbody id="ngDowntimeBody">
<tr ng-repeat="previousdowntime in GetPreviousDowntimeEvents.PreviousDowntimeEvents">
<td>{{previousdowntime.CategoryId}}</td>
<td>{{previousdowntime.StartTime}}</td>
<td>{{previousdowntime.EndTime}}</td>
<td>{{previousdowntime.Comment}}</td>
</tr>
</tbody>
</table>
I guess you do not need this new staff there
instead of
ngAppModule.controller('DowntimeController', ['$scope','$http', function ($scope, $http) {
$scope.GetPreviousDowntimeEvents = new GetPreviousDowntimeEvents($http);
}]);
use either
ngAppModule.controller('DowntimeController', ['$scope','$http', GetPreviousDowntimeEvents]);
or return something in your GetPreviousDowntimeEvents function
function GetPreviousDowntimeEvents($http) {
//...
return self;
}
I got this directive:
.directive('studentTable', [function() {
return {
restrict: 'A',
replace: true,
scope: {
students: "=",
collapsedTableRows: "="
},
templateUrl: 'partials/studentTable.html',
link: function(scope, elem, attrs) {
...
}
}
}
Template:
<table class="table">
<thead>
<tr>
<th><b>Name</b></th>
<th><b>Surname</b></th>
<th><b>Group</b></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="student in students track by $index">
<td>{{ student.name }}</td>
<td>{{ student.surname }}</td>
<td>{{ student.group }}</td>
</tr>
</tbody>
</table>
Use directive in my html like this:
<div student-table students="students"
collapsedTableRows="collapsedTableRows"></div>
And the parent controller:
.controller('SchoolController', ['$scope', 'User', function($scope, User){
$scope.students = [];
$scope.collapsedTableRows = [];
$scope.search = function(value) {
if(value) {
var orgId = $state.params.id;
var search = User.searchByOrg(orgId, value);
search.success(function (data) {
$scope.students = data;
$scope.collapsedTableRows = [];
_(data).forEach(function () {
$scope.collapsedTableRows.push(true);
});
});
}
}
}])
Now at the beginnig, the table is empty, because no users in students array. After I click search, and get list of students object, I put them to scope variable, but the directive does not update, neither it find change in model (scope.$watch('students',...). What am I missing?
P.S. If I simulate the data using $httpBackend, directive works as it should.
Please make sure that data object returning array of student because somtimes you have to use data.data that simple demo should helps you:
http://plnkr.co/edit/UMHfzD4oSCv27PnD6Y6v?p=preview
$http.get('studen.json').then(function(students) {
$scope.students = students.data; //<-students.data here
},
function(msg) {
console.log(msg)
})
You should try changing the controller this way
...
$scope.$apply(function() {
$scope.students = data;
})
...
This will start a digest loop, if it's not already in progress.
Another form that will do almost the same thing is this:
...
$scope.students = data;
$scope.$digest()
...
PS:
The first method is just a wrapper that execute a $rootScope.$digest() after evaluating the function, considering that a $digest evaluates the current scope and all it's children calling it on the $rootScope is pretty heavy.
So the second method should be preferred if it works.