This question already has answers here:
How to $http Synchronous call with AngularJS
(7 answers)
Closed 5 years ago.
Hi Everyone I have the following due to some situation on one of my projects.
I'm working with angular-xeditable, it has a method onbefore save which should returns a string in case I want the from to maintain opened(editable) and true in case I want to form to be closed(not editable).
Now the problem, below you will find my code for one angular function
self.validateBeforeSave = function(data, id){
var current_id = id;
$http.post('data/functions.php', {
action : 'updateQuotasDisease',
sqlPeriod : data.period,
sqlDiseaseCode : data.disease_code,
sqlTargetCountry : data.target_country,
sqlTargetSpecialty : data.target_specialty,
sqlChartsAmount : data.charts_amount,
sqlAmount : data.amount,
sqlStatus : data.status
})
.success(function(response) {
if(response == 'quota-exists'){
$("#"+current_id).css("background-color", "#ffc4c4");
swal("That quota already exists!", "", "error");
return "error-msg";
}
else{
$("#"+current_id).css("background-color", "#ffffff");
return true;
}
})
.error(function(response) {
console.log('Error: ' + response);
});
};
This code is being called from this HTML, but basically what matters is the need of a return from previous functions of true or "string", you can find onbeforesave="$ctrl.validateBeforeSave($data, line.id)" from there I'm calling the previous function.
<table class="table general-tables table-responsive" ng-show="$ctrl.VisibleQuotasDisease">
<thead>
<tr>
<th>Actions</th>
<th>Period</th>
<th>Disease code</th>
<th>Target country</th>
<th>Target specialty</th>
<th>Charts amount</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="line in $ctrl.quotasDisease" id="{{line.id}}">
<td style="white-space: nowrap">
<!-- onaftersave="$ctrl.saveRowDisease($data, line.id, line) validateBeforeSave" -->
<form editable-form name="rowform" onbeforesave="$ctrl.validateBeforeSave($data, line.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == line">
<button type="submit" ng-disabled="rowform.$waiting" class="btn btn-xs btn-primary">
<i class="fa fa-2x fa-save"></i>
</button>
<button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel()" class="btn btn-xs btn-default">
<i class="fa fa-2x fa-close"></i>
</button>
</form>
<div class="buttons" ng-show="!rowform.$visible">
<button class="btn btn-xs btn-warning" ng-click="rowform.$show()">
<i class="fa fa-2x fa-edit"></i>
</button>
<button class="btn btn-xs btn-danger" ng-click="$ctrl.removeRowDisease($index, line)">
<i class="fa fa-2x fa-trash-o"></i>
</button>
</div>
</td>
<td>
<span editable-text="line.period" e-class="period-inputs" e-name="period" e-form="rowform" e-maxlength="7" e-required>
{{line.period}}
</span>
</td>
<td>
<span editable-text="line.disease_code" e-name="disease_code" e-form="rowform" e-maxlength="2" e-required>
{{line.disease_code}}
</span>
</td>
<td>
<span editable-text="line.target_country" e-name="target_country" e-form="rowform" e-maxlength="2" e-required>
{{line.target_country}}
</span>
</td>
<td>
<span editable-text="line.target_specialty" e-name="target_specialty" e-form="rowform" e-maxlength="4" e-required>
{{line.target_specialty}}
</span>
</td>
<td>
<span editable-text="line.charts_amount" e-name="charts_amount" e-form="rowform" e-onkeypress="return onlyInt(event)" e-required>
{{line.charts_amount}}
</span>
</td>
<td>
<span editable-text="line.amount" e-name="amount" e-form="rowform" e-onkeypress="return onlyInt(event)" e-required>
{{line.amount}}
</span>
</td>
<td>
<span editable-text="line.status" e-name="status" e-form="rowform" e-onkeypress="return onlyInt(event)" e-required>
{{line.status}}
</span>
</td>
</tr>
</tbody>
</table>
Finnaly I want to do the question how can I do a return from inside the success section of $http post or how can I workaround to solve this situation.
Thanks in advance.
Just as another piece of code here the php function that I'm calling
if($request -> action == 'updateQuotasDisease'){
$period_sql = $request -> sqlPeriod;
$disease_code_sql = $request -> sqlDiseaseCode;
$target_country_sql = $request -> sqlTargetCountry;
$target_specialty_sql = $request -> sqlTargetSpecialty;
$charts_amount_sql = $request -> sqlChartsAmount;
$amount_sql = $request -> sqlAmount;
$status_sql = $request -> sqlStatus;
$existing_record = connDB() -> getOne("SELECT count(*) FROM quota_period WHERE period_field = '$period_sql' AND disease_code_numeric = '$disease_code_sql' AND targeted_country = '$target_country_sql' AND targeted_specialty_numeric_code = '$target_specialty_sql' AND amount = $amount_sql AND patient_cases_amount = $charts_amount_sql AND status = $status_sql;");
if($existing_record < 1){
connDB() -> query("UPDATE quota_period SET period_field = '$period_sql', disease_code_numeric = '$disease_code_sql', targeted_country = '$target_country_sql', targeted_specialty_numeric_code = '$target_specialty_sql', patient_cases_amount = $charts_amount_sql, amount = $amount_sql, status = $status_sql WHERE period_field = '$period_sql' AND disease_code_numeric = '$disease_code_sql' AND targeted_country = '$target_country_sql' AND targeted_specialty_numeric_code = '$target_specialty_sql';");
}
else{
echo "quota-exists";
}
}
First of all, your return is returning only to success call/caller. It can't be caught outside from success.
The second thought is from the ajax call. http post from angular was written to be always asynchronous. So, your function will never wait for the ajax request be completed.
But you can use the $q module to make the function will "wait" and receive the result to return it.
It's something like this:
function() {
var deferred = $q.defer();
$http.post('data/functions.php', arguments);
.success(function(response) {
//your code
//resolve the promise
deferred.resolve('request successful');
})
.error(function(data,status,headers,config){
//reject the promise
deferred.reject('ERROR');
});
return deferred.promise;
}
You only may to ensured the result which you want from deferred.promise (which I don't know that).
You can see a bit more in these links above:
To then() or to success() in AngularJS
How to $http Synchronous call with AngularJS
how to make synchronous http request in angular js
Related
Just to have an example. After I click the button it should move the row into another table in the database just like it is shown here and delete it afterwards. After I click the approve button the data row should transfer to another table in database. I really don't know how to start something like this in Laravel and I really can't find something related.
Refer to this image
Here's my view.blade.php
<table class="table table-striped table-bordered tbl_pendingres" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th hidden>Id</th>
<th>Name</th>
<th>Equipment</th>
<th>Reservation Date</th>
<th>Room</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach ($app as $resdata)
<tr>
<td hidden>{{$resdata->id}} </td>
<td>{{$resdata->name}}</td>
<td>{{$resdata->Name_item}}</td>
<td>{{$resdata->dt_item}}</td>
<td>{{$resdata->room_item}} </td>
<td>
<form action="admin.reservations.store{{ $resdata->id}}" method="POST">
{{ csrf_field() }}
<button type="submit" class="btn btn-primary btn-sm">
Accept
<i class="fas fa-chevron-right"></i>
</button></a>
</form>
<button type="button" class="btn btn-danger btn-sm">
Cancel
<i class="fas fa-times"></i>
</button>
</td>
</tr>
#endforeach
</tbody>
</table>
Here's my reservation controller
public function store($id)
{
$first = Reservation::find($id); //this will select the row with the given id
// now save the data in the variables;
$ab = $first->name;
$cd = $first->Name_item;
$ef = $first->dt_item;
$gh = $first->room_item;
$ij = $first->ldate_item;
$second = new AcceptedReservation();
$second->a_name = $ab;
$second->a_nitem = $cd;
$second->a_ditem = $ef;
$second->a_ritem = $gh;
$second->a_ldateitem = $ij;
$second->save();
// then return to your view or whatever you want to do
return view('admin.reservations.index')->with('message','Reservation Accepted');
}
Also when I clicking the button it always having error
Too few arguments to function
App\Http\Controllers\Admin\ReservationsController::store(), 0 passed in C:\laragon\www\ecmtech\vendor\laravel\framework\src\Illuminate\Routing\Controller.php on line 54 and exactly 1 expected
keep the store function empty remove $id also .like this
public function store()
{
// do nothing
}
Create a new function like this in the controller
public function acceptReservation(Request $request, $id)
{
$first = Reservation::find($id); //this will select the row with the given id
//now save the data in the variables;
$ab = $first->name;
$cd = $first->Name_item;
$ef = $first->dt_item;
$gh = $first->room_item;
$ij = $first->ldate_item;
$second = new AcceptedReservation();
$second->a_name = $ab;
$second->a_nitem = $cd;
$second->a_ditem = $ef;
$second->a_ritem = $gh;
$second->a_ldateitem = $ij;
$second->save();
/// IF YOU NEED TO REMOVE 1st TABLE VALUE
$first->delete();
//then return to your view or whatever you want to do
return redirect()->route('admin.reservations.index')->with('message','Reservation Accepted');
}
now DEFINE The ROUTE Like this
Route::post('reservation-accept/{id}', [ReservationsController::class,'acceptReservation'])->name('reservation.accept');
Now where you are adding the accept button add it call it like this
<form action="{{route('admin.reservation.accept',$resdata->id)}}" method="POST">
#csrf
<button type="submit" class="btn btn-primary btn-sm" >Accept <i class="fas fa-chevron-right"></i></button></a>
</form>
I have an array of values I'm displaying in a table. When I don't order them, my removal code works exactly as intended. I would like to order the values in the ng-repeat to group the data by role name, but that makes my splice function remove the wrong value. What is the correct way to remove my selected value?
Html that works:
<tbody data-ng-repeat="oneUserRole in ui.userRoleResultsList track by $index">
<tr>
<td>{{oneUserRole.UserId}}</td>
<td>{{oneUserRole.RoleName}}</td>
<td>{{oneUserRole.Details}}</td>
<td class="text-center">
<button type="button" class="btn btn-sm btn-danger" title="Delete" data-ng-click="ui.removeUserRole($index)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
<td>
</tr>
<tbody>
Html that doesn't work (sorts as desired, but removal doesn't work due to issue with index):
<tbody data-ng-repeat="oneUserRole in ui.userRoleResultsList | orderBy: 'RoleName' track by $index">
<tr>
<td>{{oneUserRole.UserId}}</td>
<td>{{oneUserRole.RoleName}}</td>
<td>{{oneUserRole.Details}}</td>
<td class="text-center">
<button type="button" class="btn btn-sm btn-danger" title="Delete" data-ng-click="ui.removeUserRole($index)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
<td>
</tr>
<tbody>
JavaScript:
$scope.ui.removeUserRole = function (index) {
// remove row from array.
$scope.ui.userRoleResultsList.splice(index, 1);
// other code to remove selected item from db omitted here.
}
If u would change
<button type="button" class="btn btn-sm btn-danger" title="Delete" data-ng-click="ui.removeUserRole($index)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
to
<button type="button" class="btn btn-sm btn-danger" title="Delete" data-ng-click="ui.removeUserRole({oneUserRole.UserId)"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
And then make it filter out on userId like so :
$scope.ui.removeUserRole = function (userId) {
for(let i = $scope.ui.userRoleResultsList.length; i > 0; i--) {
if(userId == $scope.ui.userRoleResultsList[i]) {
$scope.ui.userRoleResultsList.splice(i, 1);
break;
}
}
}
It should work I think
I ended up trying the suggestions of both Jelle and Frank Modica. Thanks to each of you for your quick responses. The most efficient way was to pre-filter the list coming from the controller, rather than change the html.
Here is my controller function that gets the data into the $scope.ui.userRoleResultsList:
// ******************************************************************
// Get the existing active User Roles
// ******************************************************************
function LoadUserRoleResultsList() {
var errorSummary = 'Error retrieving UserRoles list';
$scope.ui.userRoleResultsList = [];
$scope.promise =
$http.get(appConfig.GetRootUrl() + '/AdminUserRoles/UserRoleList')
.then(function onSuccess(response) {
var result = apiResponseParser.Parse(response);
if (result.isSuccessful && result.data !== null) {
// presort by rolename.
$scope.ui.ddlUserRoleTypes = result.data;
$scope.ui.userRoleResultsList = $filter('orderBy')($scope.ui.ddlUserRoleTypes, 'RoleName');
}
else {
ReportErrorMessage(errorSummary, result.message);
}
})
.catch(function onError(response) {
console.log(response, " = caught response Error");
ReportHttpError(errorSummary, response);
});
}
The magic is in the two lines after the // presort by rolename comment.
I have to scroll in a particular block(in may case table) when I will click on button.
vm.uploadOmrFile = function() {
vm.formSubmitted = true;
if (!vm.partners) {
return;
} else if (!vm.omrConfigurations) {
return;
} else if (!vm.schools) {
return;
} else if (!vm.classes) {
return;
}
formdata.append('classId', vm.configuration.classId);
// formdata.append('omrConfigId', vm.configuration.omrConfigId);
formdata.append('schoolId', vm.configuration.schoolId);
// formdata.append('tenantId', vm.configuration.tenantId);
var request = {
method: 'POST',
url: xxxxxx,
data: formdata,
transformRequest : angular.identity,
headers: {
'Content-Type': undefined
}
};
// SEND THE FILES.
$http(request)
.success(function (d) {
vm.badrecords = 0;
vm.uploadresponse = d;
vm.records = d.studentAssessments;
vm.records.forEach(function(record){
if(record.output.type == 'invalid-csv') {
vm.badrecords += 1;
}
})
})
.error(function (error) {
toastr(error);
});
setTimeout(function() {
// set the location.hash to the id of
// the element you wish to scroll to.
$location.path('/omr-upload');
$location.hash('message');
$anchorScroll();
}, 20000);
}
This is html file
<!doctype html>
<html>
<div class="modal-footer">
<button ng-click="vm.uploadOmrFile()" formnovalidate
class="btn btn-success" value="Upload"
dismiss="modal">Upload</button>
<button type="button" class="btn btn-danger" data-
dismiss="modal">Cancel</button>
</div>
<tr>
<td class="nopadding noborder">
<table class="table">
<tr>
<td colspan="4">
<div class="alert alert-danger" id="message" ng-
if="vm.uploadresponse vm.uploadresponse.hasError"
role="alert">{{vm.uploadresponse.hasError}}
<strong>{{vm.uploadresponse.message}}</strong>
<br> Total Records Parsed:{{vm.records.length}}
<br>RecordsError: {{vm.badrecords}}
</div>
<div class="alert alert-success" id="message" ng-
if="vm.uploadresponse && !vm.uploadresponse.hasError">
<strong>{{vm.uploadresponse.message}}</strong>
<br> Total Records Parsed : {{vm.records.length}}
<br>Records with Error: 0
</div>
</td>
</tr>
<tr ng-if="vm.uploadresponse &&
vm.uploadresponse.hasError">
<th>Name</th>
<th>Sheet ID</th>
<th>Record Type</th>
<th>Messages</th>
</tr>
<tr ng-repeat="record in vm.records" ng-
if="vm.uploadresponse && vm.uploadresponse.hasError">
<td>{{record.name}}</td>
<td>{{record.omrsheet}}</td>
<td>{{record.output.type}}</td>
<td>
<div style="height:100px;overflow-y:scroll">
<div ng-repeat="msg in record.output.messages"
class="error">
<p>{{msg}}</p>
</div>
</div>
</td>
</tr>
<tr ng-if="vm.uploadresponse &&
!vm.uploadresponse.hasError">
<td>
<h2><i class="glyphicon glyphicon-thumbs-up" aria-
hidden="true"></i> All records fine!
<button class="btn btn-warning btn-lg" ng-
click="vm.saveOMR()">Click to Save OMR
data</button>
</h2>
</td>
</tr>
</table>
</td>
</tr>
</html>
My problem is when i Click to upload button It should go table section of html and upload button calling "uploadOmrFile()".
In my case scroll not going to table section.
I am using id as "message", which is uses location.hash.
setTimeout(function()
{
document.getElementById('message').scrollIntoView({block: 'start',
behavior: 'smooth'}); },1000);`
Paste This code After getting response
I have tried to implement this paging solution that I found online from this link:
http://jasonwatmore.com/post/2016/01/31/AngularJS-Pagination-Example-with-Logic-like-Google.aspx
I think the issue is in the way the functions are called, because the setPage function gets called before I have all my data so it does not know how many total items there are to be displayed etc. Can someone take a quick look and see what I'm doing wrong?
function HistoryController($window, $scope, $modal, $state, toaster, PagerService, HistoryFactory, $timeout) {
var vm = this;
vm.uploads = [];
vm.includeCancelled = false;
vm.uploadDataModal = {};
vm.pager = {};
vm.setPage = setPage;
activate();
function activate() {
getHistory();
vm.setPage(1);
}
function setPage(page) {
if (page < 1 || page > vm.pager.totalPages) {
return;
}
// get pager object from service
vm.pager = PagerService.GetPager(vm.uploads.length, page);
// get current page of items
vm.items = vm.uploads.slice(vm.pager.startIndex, vm.pager.endIndex + 1);
}
function getHistory() {
HistoryFactory.getHistory(vm.includeCancelled).then(
function(response) {
_.each(response.data, function(upload) {
upload.inProgress = upload.status && ['INPROGRESS','NEW'].indexOf(upload.status.statusCd.trim()) > -1;
});
vm.uploads = response.data;
if($state.params.reupload){
uploadProductionData();
$state.params.reupload = false;
}
});
}
Here is the html
<div class="chrthdr" ui-view="header"></div>
<div id="userResults">
<div class="card card-full-width">
<div class="card-header dark-blue">
<a class="card-config" data-toggle="uploadHistory" data-placement="left"><i class="glyphicon glyphicon-info-sign"></i></a>
<div class="card-title">Data History</div>
</div>
<div class='form-horizontal range-date' style="overflow-y: auto;">
<form>
<div class="panel-body">
<div>
<span class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; margin-right: 5px" type="button" ng-click="vm.uploadProductionData()">Upload Data</span>
<label>
<input type="checkbox" ng-model="vm.includeCancelled">Include removed executions
</label>
<!--<span class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; margin-left: 5px" type="button" ng-click="vm.viewTemplates()">Download Template</span>-->
</div>
<div>
<table class="table">
<tr>
<th>Upload Date</th>
<th>Product</th>
<th>Comments</th>
<th>Template</th>
<th>Last Updated By</th>
<th>Last Updated</th>
<th>Status</th>
<th>Actions</th>
</tr>
<tr ng-repeat="upload in vm.uploads | orderBy:'uploadDate':true">
<td style="white-space: nowrap;">{{upload.uploadDate}}</td>
<td>{{upload.product}}</td>
<td style="white-space: nowrap;">{{upload.comments}}</td>
<td style="white-space: nowrap;">{{upload.templateName}}</td>
<td style="white-space: nowrap;">{{upload.lastUpdatedByUser}}</td>
<td style="white-space: nowrap;">{{upload.lastUpdateDate}}</td>
<td style="white-space: nowrap;">{{upload.status.statusName}}</td>
<td>
<button class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; " ng-hide="upload.status.statusCd === 'NEW' || upload.status.statusCd === 'ERROR'" ng-click="vm.loadStagingPage(upload.dataLoadExecutionId, upload.product, upload.status)">View</button>
<span class="btn btn-primary btn-xs pull-left" style="margin-bottom: 5px; " type="button" ng-click="vm.cancelDataExecution(upload.dataLoadExecutionId)" ng-show="upload.inProgress || upload.status.statusCd === 'ERROR'">Remove</span>
</td>
</tr>
</table>
</div>
<div class="text-center">
<ul ng-if="vm.pager.pages.length" class="pagination">
<li ng-class="{disabled:vm.pager.currentPage === 1}">
<a ng-click="vm.setPage(1)">First</a>
</li>
<li ng-class="{disabled:vm.pager.currentPage === 1}">
<a ng-click="vm.setPage(vm.pager.currentPage - 1)">Previous</a>
</li>
<li ng-repeat="page in vm.pager.pages" ng-class="{active:vm.pager.currentPage === page}">
<a ng-click="vm.setPage(page)">{{page}}</a>
</li>
<li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
<a ng-click="vm.setPage(vm.pager.currentPage + 1)">Next</a>
</li>
<li ng-class="{disabled:vm.pager.currentPage === vm.pager.totalPages}">
<a ng-click="vm.setPage(vm.pager.totalPages)">Last</a>
</li>
</ul>
</div>
</div>
</form>
</div>
</div>
This is a very common mistake of not understanding asynchronous calls.
HistoryFactory.getHistory(vm.includeCancelled).then({}) is async, meaning that it will make the call and then continue executing code after the async call. When the async call has finished, the code inside .then({}) will then execute which could be 5 milliseconds or 5 seconds.
So here:
function activate() {
getHistory(); // async call, doesn't wait
vm.setPage(1); // executed immediately after, data not ready
}
Needs to be:
function activate() {
getHistory();
}
And changegetHistory() to:
function getHistory() {
HistoryFactory.getHistory(vm.includeCancelled).then(
function(response) {
_.each(response.data, function(upload) {
upload.inProgress = upload.status && ['INPROGRESS','NEW'].indexOf(upload.status.statusCd.trim()) > -1;
});
vm.uploads = response.data;
if($state.params.reupload){
uploadProductionData();
$state.params.reupload = false;
}
// Now call setPage after data is finished
vm.setPage(1);
});
}
I do project using Laravel 5. I show table from view and I want to when click this link pass it is data value all data to JavaScript function. I am try to several way but cannot do it.
#foreach ($basl_officers as $basl_officer)
<tr>
<td><a href="#" onClick="functionOne($basl_officer)" >{{ $basl_officer->officerName }} </a></td>
<td align='center'>
{!! Form::open(['method' => 'DELETE', 'route'=>['basl_officers_page.destroy',$basl_officer->id]]) !!}
<span class="glyphicon glyphicon-pencil"></span>    
<button type="submit" class="btn btn-default btn-sm" onclick="return confirm('Are you sure?')"> <span class="glyphicon glyphicon-trash"></span> </button>
{!! Form::close() !!}
</td>
</tr>
#endforeach
JavaScript Code
<script type="text/javascript">
function functionOne(x) {
alert('You clicked the top text' + x);
}
function functionTwo() {
alert('You clicked the bottom text');
}
You could try this:
onClick="functionOne({{ json_encode($basl_officer) }})"
I got this to work using this code inside my .blade file.
<script>
var object = <?php echo json_encode($object) ?>;
console.log(object);
</script>
This is assuming object is provided through your controller.