I have a simple AngularJS app that shows a table with data on an ng-repeat after the user logins. I'm having an issue where after logging in, the table briefly shows blank rows and then the actual rows with data. Any suggestions on how to fix this?
This is the controller for the login:
$scope.login = function(user) {
loginSrvc.login(user).then(function(response) {
if (response == "authentication failed") {
$scope.error = true;
$scope.user = {};
$location.path("/");
} else {
if (response.group_name == "On Site Registration"){
var data = {
event: response.zk_event_id,
group: response.zk_group_id
};
$scope.getAvailableCamper(data);
}
else if (!response.zk_group_id) {
$location.path("/form/" + response.zkp_camper_id);
}
else {
$location.path("/dashboard/" + response.zk_event_id + "/" + response.zk_group_id);
}
}
})
}
$scope.getAvailableCamper = function(data) {
dashboardSrvc.fetchGroup(data).then(function(response){
var findAvailableCamper = _.find(response.data, {status: null});
console.log("this is find", findAvailableCamper);
var id = findAvailableCamper.zkp_camper_id;
$location.path("/onSiteForm/" + id);
})
}
This is the controller for the table:
$scope.campers = function() {
$scope.camper = loginSrvc.getCampers();
}
$scope.campers();
$scope.fetchCampers = function(id) {
dashboardSrvc.fetchCampers(id).then(function(response){
$location.path("/form/" + id);
})
}
Here's the html code for table:
<tr ng-repeat="campers in camper">
<td>{{$index + 1}}</td>
<td>{{campers.name_first}}</td>
<td>{{campers.name_last}}</td>
<td><button type="submit" name="submit" ng-click="register(campers)" class="btn btn-success" role="button" ng-hide="campers.status == 'Submitted' " ng-disabled="!(!!campers.name_first && !!campers.name_last && !!campers.gender && !!campers.city && !!campers.date_of_birth && !!campers.email && !!campers.emergency_cell_phone && !!campers.emergency_contact_first_name && !!campers.emergency_contact_last_name && !!campers.emergency_home_phone && !!campers.relationship_to_camper && !!campers.first_time_flag )">Submit</button> <p ng-show ="campers.status == 'Submitted'" > {{campers.registration_date | date: 'medium'}}
</p>
</td>
<td>{{campers.status}}</td>
<td>
<button ng-click="fetchCampers(campers.zkp_camper_id)" type="submit" name="view" class="btn btn-default" role="button" ng-show="campers.status == 'Submitted' "><span class="glyphicon glyphicon-eye-open"></span></button>
<button ng-click="fetchCampers(campers.zkp_camper_id)" type="submit" name="edit" class="btn btn-default" role="button" ng-hide="campers.status == 'Submitted' " ><span class="glyphicon glyphicon-edit"></span></button>
<button type="button" ng-click="setValue(campers.zkp_camper_id)" name="deleteModalLauncher" id="deleteModalLauncher" class="btn btn-danger" role="button" data-toggle="modal" data-target="#deleteModal" ng-hide="campers.status == 'Submitted' " ><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</td>
</tr>
I really appreciate the help! Thanks!
There is a directive to minimize flickering that angular loop does while check bindings and all. it is called ng-cloak and it can be added to any element on your view.
More info : https://www.w3schools.com/angular/ng_ng-cloak.asp
...
You can also use angularjs event who is fired when content is fully loaded and set a flag ex. loaded = true and then use ng-show with loaded variable.
Controller :
$scope.$on('$viewContentLoaded', function(){
$scope.loaded = true;
});
View :
<table ng-show="loaded">
.....
</table>
Hope that helps!
Related
I have to implement the share product functionality with the user after share i have to refresh the list here selectedSharedIntermediaryInAlbum is our array so how to implement this?
//refreshSharedIntermediary for refresh the lsit
$scope.refreshSharedIntermediary = function() {
$scope.selectedSharedIntermediaryInAlbum = $scope.selectedSharedIntermediaryInAlbum;
}
<div class="w3-right">
<button class="btn btn-rose btn-sm" tltle="refresh data" ng-click="refreshSharedIntermediary()">
<i class="glyphicon glyphicon-repeat"></i>
</button>
</div>
You can use $scope.reload function where need to reload the list ... i have used below concept :
<div class="well well-lg" ng-repeat="item in list track by item.id">
<button class="btn btn-default"
ng-click="collapsedFlags[item.id] = !collapsedFlags[item.id]">
{{ item.isCollapsed ? '+' : '-' }}
</button>
<div uib-collapse="collapsedFlags[item.id]" ng-bind="item.value"></div>
</div>
$scope.reload = function () {
$http.get('list.json').then(function (data) {
$scope.list = data && data.data || [];
});
};
$scope.collapsedFlags = {};
$scope.reload();
Working example : https://plnkr.co/edit/87vVb8Jjyz6yFGAjiHBK?p=preview
I am new to using angular js, I'm confused, I have code like this
angular.module("sportStore")
.constant("productListActiveClass", "btn-primary")
.controller("productListCtrl", function($scope, $filter, productListActiveClass) {
var selectedCategory = null;
$scope.selectCategory = function(newCategory) {
selectedCategory = newCategory;
}
$scope.categoryFilterFn = function(product) {
return selectedCategory == null ||
product.category == selectedCategory;
}
$scope.getCategoryClass = function(category) {
return selectedCategory == category ? productListActiveClass : "";
}
});
<div class="panel panel-default row" ng-controller="productListCtrl">
<div class="col-xs-3">
<a ng-click="selectCategory()" class="btn btn-block btn-default btn-lg">Home</a>
<a ng-repeat="item in data.products | orderBy:'category' | unique: 'category'" ng-click="selectCategory(item.category)" class="btn btn-block btn-default btn-lg" ng-class="getCategoryClass(item.category)">
{{item.category}}</a>
</div>
</div>
then when i try it, result in chrome as follows:
result in chrome
and in firefox as follows:
result on firefox
can somebody tell me why this happened? ng-class work on firefox but not in chrome. thanks in advance.
I've found that cache in chrome must be cleaned before. it worked now in chrome.
I have a simple ng-click button at the moment that adds rows with the row and number.
What im wanting is to add a new segment of code which is this:
<div class="btn btn-info btn-sm" style="display:inline-block" ngf-select="uploadinv($file)">Upload Attachment</div>
<p style="display:inline-block;" ng-if="filenameinv">Uploaded file</p>
<button type="button" ng-click="deleteAtt(file)" class="btn btn-danger btn-sm">
<i class="fa fa-trash-o"></i>
</button>
<button type="button" ng-click="addAtt()" class="btn btn-info btn-sm">
<i class="fa fa-plus"></i>
</button>
Heres what i have in my controller
$scope.rows = ['Row 1', 'Row 2'];
$scope.counter = 3;
$scope.addAtt = function() {
$scope.rows.push('Row ' + $scope.counter);
$scope.counter++;
};
I'm wanting to adapt the controller code to make it work with copying the code above up to 5 items. And ideally on each new item the plus button from the previous would disappear so there would always only be one button.
Basically at the moment there is one upload button. With a delete and plus button that appears when a file is uploaded. What i'm wanting is when a user wants to upload another file said user can click the plus button and another uploader will appear. I also need to get this saving against the db but thats another headache!
Heres the uploader
$scope.uploadinv = function (file) {
if (file) {
Upload.upload({
url: '',
data: {file: file}
}).then(function (resp) {
sweetAlert({title: "Attachment Saved", type: "success"});
}, function (resp) {
sweetAlert({title: "Attachment Not Saved", type: "error"});
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
$scope.event.filenameinv = evt.config.data.file.name
});
}
};
This is the bit i've done so far
$scope.fileUploadRows = [];
var fileDetails = {
fileName: $scope.event.filenameinv
}
$scope.fileUploadRows.push(fileDetails);
$scope.counter = 1;
$scope.addInvAttachment = function() {
var fileDetails = {
fileName: $scope.event.filenameinv
}
$scope.fileUploadRows.push(fileDetails);
$scope.counter++;
}
May be this could help:
<div class="row" ng-repeat="row in rows track by $index">
<div class="btn btn-info btn-sm" style="display:inline-block" ngf-select="uploadinv($file)">Upload Attachment</div>
<p style="display:inline-block;" ng-if="fileUploadRows[$index].filename">Uploaded file</p>
<button type="button" ng-click="deleteAtt(file)" class="btn btn-danger btn-sm">
<i class="fa fa-trash-o"></i>
</button>
<button type="button" ng-if="$last" ng-click="addAtt()" class="btn btn-info btn-sm">
<i class="fa fa-plus"></i>
</button>
</div>
Please note that you probably should handle (array of) filenameinv somehow. You didn't show in your code how you use/intialize this variable.
EDIT: See updated markup above. The trick is to have the appropriate $index. I think you should also call addInvAttachment() function, probably in the sucess then of the upload.
I've tried several solutions on other answers but so far none has worked as needed, basically I need to disable a button (anchor) if the form is invalid, disabling is not the problem, avoiding the call to the function is.
For that I tried something like this:
<a class="btn icon-btn btn-success" ng-disabled="myForm.$invalid" novalidate ng-submit="myForm.$valid && submit.addOrEditItem()">
<span class="glyphicon btn-glyphicon glyphicon-save img-circle text-success"></span>Save</a>
And on my controller:
$scope.isCreating = true;
$scope.submit = {
addOrEdit: function() {
if($scope.isCreating){
$scope.items.push({type: $scope.newItem.name, description: $scope.newItem.descriptions, isDone:false, editable:false});
}else{
$scope.eItem.type = $scope.newItem.name;
$scope.eItem.description = $scope.newItem.descriptions;
}
$scope.isCreating = true;
$scope.newItem = {};
}
}
Is there any alternatives for this?
Instead of ng-submit, use ng-click:
<a class="btn icon-btn btn-success" ng-disabled="myForm.$invalid" novalidate ng-click="myForm.$valid && submit.addOrEdit()">
I have been through a few of those questions on Stackoverflow and found this link from a thread:http://toddmotto.com/everything-about-custom-filters-in-angular-js/ which is great but I am struggling to adapt it to what I need to do.
I am trying to implement a simple function based on it which will have a button group one which shows all results then from and to letter such as:
<button type="button" class="btn btn-primary">All</button>
<button type="button" class="btn btn-primary”>A-E</button>
<button type="button" class="btn btn-primary">F-K</button>
<button type="button" class="btn btn-primary">L-P</button>
However I am unable to adapt the function to perform this filter. I can only do with the basic filter by single letter.
<button type="button" class="btn btn-primary" ng-click="letter = 'C'">C</button>
I am also unable to show “all results"
Here is my app code:
var app = angular.module (‘app', []);
app.controller('PersonCtrl', function () {
this.friends = [{
name: 'Andrew'
},
{
name: 'Bob'
},{
name: 'Beano'
},{
name: 'Chris'
}, {
name: 'Will'
}, {
name: 'Mark'
}, {
name: 'Alice'
}, {
name: 'Todd'
}];
});
app.filter('startsWithLetter', function () {
return function (items, letter) {
var filtered = [];
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (letterMatch.test(item.name.substring(0, 1))) {
filtered.push(item);
}
}
return filtered;
};
});
HTML CONTROLLER CODE:
<div class="container" ng-controller="PersonCtrl as person">
<ul>
<li ng-repeat="friend in person.friends | startsWithLetter:letter">
{{ friend }}
</li>
</ul>
</div>
How do I adapt this to perform more specific filtering?
You can use colons to pass multiple arguments to your filter - fromLetter and toLetter as well as your input.
<li ng-repeat="friend in person.friends | startsWithLetter:person.fromLetter:person.toLetter">
{{ friend }}
</li>
Then you can lowercase the first letter of the string and compare this directly to fromLetter and toLetter
app.filter('startsWithLetter', function () {
return function (items, fromLetter, toLetter) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
var firstLetter = item.name.substring(0, 1).toLowerCase();
if ((!fromLetter || firstLetter >= fromLetter)
&& (!toLetter || firstLetter <= toLetter)) {
filtered.push(item);
}
}
return filtered;
};
});
That means that the button logic needs to be slightly more complex and set two variables:
<button type="button" class="btn btn-primary" ng-click="person.setLetters()">All</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('a','e')">A-E</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('f','k')">F-K</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('l','p')">L-P</button>
and on your controller:
this.setLetters = function(from, to){
this.fromLetter = from;
this.toLetter = to;
};
JSFiddle
You could have filtering based on the alphabet ASCII codes. On button click set the range of ASCII code using ng-click directive with - separated value like letter='65-69. Then that range will pass through the the filter, out of which first parameter is upperLimit & 2nd one is lowerLimit of the selected range. For comparing the starting variable ASCII value we could use string.charCodeAt('0') method which will return ASCII value of first character & will compare that value with the range variable inside foreach loop.
Markup
<div class="container" ng-controller="PersonCtrl as person">
<ul>
<li ng-repeat="friend in person.friends | startsWithLetter:letter">
{{ friend }}
</li>
</ul>
<button type="button" class="btn btn-primary" ng-click="letter=''">All</button>
<button type="button" class="btn btn-primary" ng-click="letter='65-69'">A-E</button>
<button type=" button " class="btn btn-primary" ng-click="letter='70-75'">F-K</button>
<button type="button " class="btn btn-primary " ng-click="letter='76-80'">L-P</button>
</div>
Filter
app.filter('startsWithLetter', function() {
return function(items, letter) {
if (!letter || letter.length == 0)
return items;
var filtered = [],
range = letter.split('-');
var letterMatch = new RegExp(letter, 'i');
for (var i = 0; i < items.length; i++) {
var item = items[i];
for (var j = parseInt(range[0]); j <= parseInt(range[1]); j++) {
if (item.name.charCodeAt('0') == j) {
filtered.push(item);
}
}
}
return filtered;
};
});
Working PLunkr