AngularJs Abort Previous service Call when New Call Performed - angularjs

I am using md auto complete for Auto Segessions. while I am entering text I want to make a server call to get the results. but I want to abort the previous server call, when I have to control that in controller script or in service script.?
<md-autocomplete flex required flex-gt-sm="25
md-selected-item="school.college_name"
md-clear-button="true"
md-input-name="school.college"
md-input-minlength="3"
md-input-maxlength="40"
md-no-cache="noCache"
md-search-text="searchText"
md-items="item in ctrl.academyschoolsList"
md-search-text-change = "ctrl.searchAcademySchools(searchText)"
md-item-text="item.name">
<md-item-template>
<span class="item-title">
<span> {{item.name}}, {{item.city}}, {{item.state}}, {{item.zip}}
</span>
</span>
</md-item-template>
<div ng-messages="ctrl.leadEntryForm.school.college.$error">
<div ng-message="required">This field is required</div>
</div>
</md-autocomplete>
function searchAcademySchools(query) {
ctrl.academyschoolsList = [];
if (query.length > 3) {
C2Services.getAcademySchools(query).then(function (data) {
angular.forEach(data, function (value, key) {
ctrl.academyschoolsList.push(value);
});
});
}
}

An XHR can't be aborted once it starts, but new results can replace old results:
function searchAcademySchools(query) {
if (query.length > 3) {
C2Services.getAcademySchools(query).then(function (data) {
ctrl.academyschoolsList = data;
});
} else {
ctrl.academyschoolsList = [];
};
}
In this example each XHR will replace the old results.

Related

md-autocomplete does not work for number field in angularjs

I am working with md-autocomplete in angularjs material. It's working fine when the search field is string. But when it's number then it's does not search as expected.
My code: HTML
<md-autocomplete ng-disabled="isDisabled"
name="DriverEMP_ID"
md-selected-item="selectedEMP_ID"
md-no-cache="ctrl.noCache"
md-search-text="driverText"
md-selected-item-change="selectedDriverEMP_IDChange(item)"
md-items="item in querySearchForDriverEMP_ID(driverText)"
md-item-text="item.display"
md-min-length="0"
placeholder="Driver ID"
required>
<md-item-template>
<span md-highlight-text="driverText" md-highlight-flags="^i">{{item.display}}</span>
</md-item-template>
<md-not-found>
No states matching "{{driverText}}" were found.
</md-not-found>
</md-autocomplete>
JS
var self = this;
var simulateQuery = false;
$scope.isDisabled = false;
self.DriverIDList = [{"value":"23869","display":"43721"},{"value":"36407","display":"48188"},{"value":"43942","display":"62924"},{"value":"13911","display":"22831"},{"value":"15531","display":"27175"},{"value":"13531","display":"21609"},{"value":"69526","display":"74854"},{"value":"14085","display":"23122"},{"value":"71018","display":"77915"}];
$scope.querySearchForDriverEMP_ID = querySearchForDriverEMP_ID;
function querySearchForDriverEMP_ID(query) {
var results = query ? self.DriverIDList.filter(createFilterForDriverID(query, objDriverIDListData)) : self.DriverIDList;
var deferred = $q.defer();
$timeout(function () { deferred.resolve(results); }, Math.random() * 1000, false);
return deferred.promise;
}
function createFilterForDriverID(query, DriverIDList) {
var lowercaseQuery = query.toString();
return function filterFn(DriverIDList) {
return (DriverIDList.display.indexOf(lowercaseQuery) !== -1);
};
}
But for string field it's working fine.
self.DriverIDList = [{"value":"23869","display":"Md. Foysal Iqbal"},{"value":"36407","display":"Md. Saiful Islam"},{"value":"43942","display":"Md.Sajib"},{"value":"13911","display":"Alamgir Hossain"},{"value":"15531","display":"Md.Hossain"},{"value":"13531","display":"Md. Masud Sheikh"},{"value":"69526","display":"Md. Sohel Rana"},{"value":"14085","display":"Monirul Islam"},{"value":"71018","display":"Md. Mohoshin Ali"},{"value":"71185","display":"Md. Al Amin"},{"value":"69306","display":"Md. Mohin Uddin"},{"value":"37269","display":"Md Anis Sardar"},{"value":"13909","display":"Md. Rafiqul Islam"},{"value":"10963","display":"Md. Shah Alam"},{"value":"13860","display":"Md. Abul Hashem"},{"value":"67752","display":"Md. Oli Ullah"},{"value":"45015","display":"Md. Abu Taher "},{"value":"560","display":"Md. Rehad Hossain Mamun"}];
Any help would be appreciated.
Why not keep it simple and just handle it right in the filter function instead of creating your own? Guessing the issue is in your filter. Try this and see if it works.
self.driverIDList.filter( item => item.display.indexOf(query.toString()) > -1);

InfiniteScroll - AngularJS not working

Edit:
Just for checking purposes, I also did a console.log inside the nextPage function, to check if it's being triggered:
$scope.nextPage = function() {
var captureLength = $scope.captures.length;
console.log('TRIGGER');
if($scope.busy) {
return;
}
...
}
};
And it seems I'm getting a infinite loop, but I can't see why.
=================================
I'm trying to implement infinitescroll into a view but for some reason it's only loading the initial 4 images and not triggering the rest.
Here is my code:
CTRL:
/* ----------------------- Variables ----------------------- */
$scope.auth = auth;
$scope.captures = [];
$scope.following = [];
$scope.allData = [];
$scope.busy = true;
var page = 0;
var step = 4;
$scope.nextPage = function() {
var captureLength = $scope.captures.length;
if($scope.busy) {
return;
}
$scope.busy = true;
$scope.captures = $scope.captures.concat($scope.allData.splice(page * step, step));
page++;
$scope.busy = false;
if($scope.captures.length === 0) {
$scope.noMoreData = true;
}
};
/* ----------------------- Process Data ----------------------- */
$q.all({follows: findFollow(), users: getUsers(), captures: getAllCaptures()}).then(function(collections) {
var follows = collections.follows;
var users = collections.users;
var captures = collections.captures;
follows.filter(function(follow) {
return follow.follower_id === auth.profile.user_id;
}).forEach(function(follow) {
users.filter(function(user) {
return user.user_id === follow.followed_id;
}).forEach(function(user) {
$scope.following.push(user);
});
});
follows.filter(function(follow) {
return follow.follower_id === auth.profile.user_id;
}).forEach(function(follow) {
captures.filter(function(capture){
return follow.followed_id === capture.userId;
}).forEach(function(capture){
console.log(capture);
$scope.allData.push(capture);
});
});
$scope.nextPage();
$scope.busy = false;
});
/* ----------------------- Retrieve Services - Data ----------------------- */
function findFollow() {
return userApi.findFollow().then(function(res) {
return res.data;
});
}
function getUsers() {
return userApi.getUsers().then(function(res) {
return res.data.users;
});
}
function getAllCaptures() {
return captureApi.getAllCaptures().then(function(res) {
return res.data;
});
}
Partial:
<div class="col-md-8">
<div class="well main-well">
<h3 class="page-header-h3">Following Dashboard:</h3>
<hr />
<h4 align="center" ng-show="!captures.length">
<strong>The people that you are following, have not posted anything yet.. Yikes!</strong>
<br /><br />
Quickly, go follow more people!</h4>
<div class="row" infinite-scroll="nextPage()" infinite-scroll-disabled="busy || noMoreData" infinite-scroll-distance="0.1">
<ul class="dynamic-grid" angular-grid="captures" ag-id="gallery">
<li data-ng-repeat="capture in captures | orderBy :'created_at':true" class="grid">
<a ui-sref="detail({id: capture._id})">
<img ng-src="{{capture.picture}}" class="grid-img" />
<span class="follow-capture-info">
<span class="follow-capture-name"><span class="glyphicon glyphicon-user"></span>
{{capture.author}}
<span class="following-capture-time">·
<span class="glyphicon glyphicon-time"></span>
<span am-time-ago="capture.created_at"></span>
</span>
</span>
</span>
</a>
</li>
</ul>
</div>
<div ng-show="busy">Loading more...</div>
</div>
Anyone know where I went wrong?
Thanks.

Angular asynchronous search filter-- Expected array but received: {0}

Trying to enable a search input for a friends array, however these friends are being grabbed async, so I get this error Expected array but received: {0}---- because the array is empty when the filter loads.... is there anyway around this?
<span class="friendHeaders">Online Friends</span>
<input type="text" width="10%" class="friendSearch" placeholder="Search friends" ng-model="searchText"/>
<div class="friendScroll" scroll-glue-top>
<ul class="friendList">
<li ng-if='friend.online' ng-repeat="friend in friends track by $index | orderBy:'name' | filter:searchText" ng-click='startChat(friend)'>
<div ng-class='(friend.username === activeFriend.username) ? "activeFriendPanel" : ""' class='panel panel-default friendPanel'>
<span ng-if="friend.service === 'Locket'" class="glyphicon glyphicon-lock" aria-hidden="true"></span>
<span ng-if="friend.service === 'Facebook'" aria-hidden="true"><img class='icon' src='../../facebook.png'/></span>
<span ng-if="friend.service !== 'Locket' && friend.service !== 'Facebook'" class='friendService'>{{friend.service}}</span>
<span class='friendName'>{{friend.name}}</span>
<span class='friendArrow'><span class="glyphicon glyphicon-chevron-right vertical-center" aria-hidden="true"></span></span>
<div class="unreadMessage" ng-if="friend.unreadMessage">
New message
</div>
</div>
</li>
</ul>
</div>
here is some of the relevant controller code
the friends array is an array of objects
var keyResponseTimeout = 15000;
angular.module('Locket.chat', ['luegg.directives', 'ngAnimate'])
.controller('chatController', function ($scope, authFactory, $stateParams, socket, encryptionFactory, $timeout) {
console.log('chat');
authFactory.signedin().then(function(resp){
if (resp.auth === 'OK') {
socket.connect();
var keyring = encryptionFactory.generateKeyPair();
var publicKey;
// send public key to friends on login
keyring.then(function (keypair) {
publicKey = keypair.pubkey;
socket.emit('sendPGP', keypair.pubkey);
});
$scope.currentUser = $stateParams.username || resp.username;
$scope.friends = [];
$scope.sentRequest = false;
function createFriendObj(username, online, name, service) {
return {
service: service || 'Locket',
username: username,
name: name || (username + ' daawwggg'),
unreadMessage: false,
online: online || false,
key: null,
messages: [],
unsentMessages: [], // added this in for revoke and show decrypted message for sender
unsentFBMessages: [], // Follows same convention. Will not work for messages from prev session
sentKey: false
};
}
// Listen for events from our extension
window.addEventListener('message', function(event) {
if (event.source != window)
return;
// Recieve a facebook friends list
if (event.data.type && (event.data.type === 'facebookFriendsList')) {
for (var i = 0; i < event.data.text.length; i++) {
var friend = event.data.text[i];
var friendObj = createFriendObj(friend.username, true, friend.name, "Facebook");
$scope.friends.push(friendObj);
}
// After receiving a facebook friends list, begin monitoring the facebook DOM
window.postMessage({ type: 'scanFacebookDOM', text: ''}, '*');
}
Figured it out, the track by index interferes with the filter. I took it out and works
I think you're suppose to keep it track by $index for performance reasons. I read that it should just be moved to the end of the function
friend in friends | orderBy:'name' | filter:searchText track by $index

could not upload properly using ng-file-upload and laravel

I am trying to implement a feature so that the user will be able to upload a profile photo for our company page. I am using ng-file-upload plugin in angular: https://github.com/danialfarid/ng-file-upload
I followed one example in the documentation for uploading a photo:
function uploadPic ( file ) {
file.upload = Upload.upload( {
url: 'api/companyprofile/upload_logo',
method: 'POST',
sendFieldsAs: 'form',
headers: {
'my-header': 'my-header-value'
},
file: file,
fileFormDataName: 'myLogo.png'
} );
file.upload.then( function ( response ) {
$timeout( function () {
file.result = response.data;
} );
}, function ( response ) {
if ( response.status > 0 )
logger.error( response )
} );
file.upload.progress( function ( evt ) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min( 100, parseInt( 100.0 * evt.loaded / evt.total ) );
} );
}
and this is it's html
<form name="myForm" enctype="multipart/form-data">
<fieldset>
<legend>Upload on form submit</legend>
<br>Photo:
<input type="file" ngf-select ng-model="picFile" name="cp_logo" accept="image/*" ngf-max-size="2MB" required>
<i ng-show="myForm.file.$error.required">*required</i>
<br>
<i ng-show="myForm.file.$error.maxSize">File too large
{{picFile.size / 1000000|number:1}}MB: max {{picFile.$errorParam}}</i>
<img ng-show="myForm.file.$valid" ngf-src="!picFile.$error && picFile" class="thumb">
<br>
<button ng-click="vm.uploadPic(picFile)">Submit</button>
<span class="progress" ng-show="picFile.progress >= 0">
<div style="width:{{picFile.progress}}%"
ng-bind="picFile.progress + '%'"></div>
</span>
<span ng-show="picFile.result">Upload Successful</span>
<span class="err" ng-show="errorMsg">{{errorMsg}}</span>
</fieldset>
<br>
</form>
The problem is that I get a status code of 200 telling me that it had uploaded the photo successfully but in reality it did not. Giving me an empty response. What am I doing wrong?
Disclaimer: I don't know php but this is the backend code from our backend developer. This might help
/**
* Upload a Company Logo (Synchronous).
* #route GET - prefix/companyprofile/upload_logo
*
* #return json
*/
public function uploadLogo()
{
// get the company profile object
$cProfile = CompanyProfile::first();
// get all inputs from the form
$input = Input::all();
// needs validation
$validator = Validator::make(Input::all(), ['cp_logo' => 'image|max:'.$this->max_filesize]);
if ($validator->fails()) {
return array('error' => $validator->messages());
}
// if there is a cp_logo store in $file variable
if($file = array_get($input,'cp_logo')) {
// delete old company logo
$this->deleteOldCompanyLogo($cProfile);
// concatenate the filename and extension
$input['filename'] = $this->generateFileName($file);
// save the company logo filename in the database
$this->saveCompanyLogo($cProfile, $input['filename']);
try {
// upload the files to the file server
Storage::disk(env('FILE_STORAGE'))->put($input['filename'], File::get($file));
return response()->json(['status' => 'Upload successful', 'filename' => $input['filename']]);
} catch(\Exception $e) {
return response()->json(['error' => $e->getMessage()], 400);
}
}
}
your backend expecting input named "cp_logo"
function uploadPic(file) {
if (!file || file.$error) {
logger.error(file);
return;
}
file.upload = Upload.upload({
url: 'api/companyprofile/upload_logo',
method: 'POST',
sendFieldsAs: 'form',
headers: {
'my-header': 'my-header-value'
},
file: file,
fileFormDataName: 'cp_logo' //<-- here is your POST data key send to server
});
and since in your html input named "cp_logo"
<input type="file" ngf-select ng-model="picFile" name="cp_logo" accept="image/*" ngf-max-size="2MB" required>
your validation expression should be.. myForm.cp_logo.$error or myForm.cp_logo.$valid
also double check upload input before send
HTML
<img ng-show="myForm.cp_logo.$valid" ngf-src="!picFile.$error && picFile" class="thumb">
<br>
<button ng-click="vm.uploadPic(picFile)" ng-disabled="!myForm.$valid" >Submit</button>
^ if this button is disabled obviously something wrong with inputs
BTW: the backend could return a status 200 (OK) when validation failed
you could check json response
file.upload.then(function(response) {
$timeout(function() {
logger.log(response.data);
if(response.data.error){
//something went wrong?
}
file.result = response.data;
});
}, function(response) {
if (response.status > 0)
logger.error(response)
});

AngularFire add in reverse order

I need to add objects to Firebase in reverse order. Or reverse data when goes data binding. Or sort objects by time of create.
var ref = new Firebase("https://[url].firebaseio.com/");
$scope.messages = $firebase(ref);
$scope.addMessage = function(e) {
$scope.messages.$add({title: $scope.title, body: $scope.msg, time: $scope.getDate() });
}
<div class="well span3 pull-left note" ng-repeat="(key, msg) in messages">
<button type='button' class='close' ng-click="messages.$remove(key)">×</button>
<b>{{msg.time| date: 'medium'}}</b>
<span>{{msg.title}}</span>
<span>{{msg.body}}</span>
<button ng-click="changeMessage(key)" class="btn btn-mini pull-right"><i class="icon-pencil"></i></button>
</div>
I try to use OrderBy atribute for ng-repeat but this is not easy because in messages are stored objects.
Check out the chat example in angularFire-seed. It uses a custom reverse filter
The reverse filter looks like so:
app.filter('reverse', function() {
function toArray(list) {
var k, out = [];
if( list ) {
if( angular.isArray(list) ) {
out = list;
}
else if( typeof(list) === 'object' ) {
for (k in list) {
if (list.hasOwnProperty(k)) { out.push(list[k]); }
}
}
}
return out;
}
return function(items) {
return toArray(items).slice().reverse();
};
});
And the usage is like so:
<ul id="messages" ng-show="messages">
<li ng-repeat="message in messages | reverse">{{message.text}}</li>
</ul>

Resources