How to populate jQuery UI Select2 with Restangular - javascript

I can't see why Restangular would behave differently inside a jquery-ui callback to the way it does anywhere else. Can you?
The following works in my controller:
Restangular.all('skills').getList().then(function(result) {
console.log(result);
});
However, when I use Restangular inside the query function for a jquery-ui-select2 (via angular-select2), it never makes a request.
HTML:
<input type="text" ui-select2="skillOptions" ng-model="skills">
JavaScript:
$scope.skillOptions = {
multiple: true,
query: function(query) {
// I see this:
console.log("Q:", query.term);
// this silently fails:
Restangular.all('skills').getList({
query: query.term
}).then(function(body) {
// this callback is never reached (nor is the error one)
var skills = body.skills;
console.log("got skills", skills);
query.callback({
data: {
text: 'name',
results: skills
}
});
}, function(error) {
console.error("Error getting skills", error);
});
}
};
Is there another way to use the query callback with Restangular or can anybody see why on Earth this wouldn't work?

The solution was to nest the callback in a $scope.$apply (since I am on AngularJS version 1.1.5) as per this bit of the documentation
Here's some working code:
$scope.skillOptions = {
multiple: true,
query: function(query) {
$scope.$apply(function() {
Restangular.all('skills').getList({
query: query.term
}).then(function(body) {
var skills;
skills = body.skills;
console.log("got skills", skills);
return query.callback({
results: _(skills).map(function(s) {
return {
text: s.name,
id: s.id
};
})
});
}, function(error) {
console.log("Error getting skills", error);
});
});
}
};

Related

Apollo Client is not refreshing data after mutation in NextJS?

Here is the page to create a User
const [createType, { loading, data }] = useMutation(CREATE_USER_CLASS) //mutation query
const createUserClass = async (event) => {
event.preventDefault();
try {
const { data } = await createType({
variables: {
userClassName,
},
refetchQueries: [{ query: STACKINFO }],
options: {
awaitRefetchQueries: true,
},
});
setNotification({
message: 'User class created successfully',
code: 200,
});
handleClose();
} catch (e) {
setNotification({ message: e.message, code: 400 });
handleClose();
}
};
The thing is I can see inside the network tab the API is calling twice, which is not a good way, but I can see the newly added data , but the page is not refreshing. Kindly help me
I was also struggling with a similar problem and I stepped into your question. I don't know which version of Apollo Client you are using, but I think that instead of using refetchQueries() method, you can try to use update() to clear the cache. This way you will notify UI of the change. Something like this:
createType({
variables: {
userClassName,
},
update(cache) {
cache.modify({
fields: {
// Field you want to udpate
},
});
},
})
This is a link for reference from official documentation's page:
https://www.apollographql.com/docs/react/data/mutations/#:~:text=12-,update
I hope it helps!

How can I pass an error message from the server backend to vue frontend

I am working on error handling for an application built in Vue/Vuetify. I am using external pagination for a datatable that links to an API that only allows so many hits in a period of time. Because of that, I'm trying to pass through and display an error of "Too Many Requests" on the front end for users when they hit that limit.
The issue I'm having though is passing that error from the backend server to the frontend. When it errors on the front end, it just gives a 500 error. However, the server log is giving me the actual error happening. How can I get that to pass? Below is the relevant javascript code from the server and the front end.
For note: I've been using eventbus to display errors throughout the project. But up until now, I haven't had to pass any from the back to front.
Backend Server
module.exports = {
async find(ctx) {
var page = ctx.query.page;
var key = '';
var locale = ({ location: '', location_type: '', page: page });
const sdk = require('api')('#');
try {
var response = await sdk.auth(key)['grants_funders'](locale);
}
catch (err) {
console.log(err);
}
;
// .then(res => console.log(res))
// .catch(err => console.error(err));
// console.log(response);
return response
}
};
FRONTEND
export default {
name: "Search",
components: {},
props: ["funderDirectories", "serverItemsLength"],
data() {
return {
page: 1,
usericon: usericon,
greentick: greentick,
listicon: listicon,
training: training,
keyword: null,
funderHeaders: [
{ text: "Organization", value: "funder_name" },
{ text: "City", value: "funder_city" },
{ text: "Country", value: "funder_country" },
{ text: "Count", value: "grant_count" },
],
myloadingvariable: false,
pageCount: 1,
itemsPerPage: 25,
};
},
watch: {
page() {
Vue.$funderService.find({ page: this.page }).then((res) => {
this.funderDirectories = res.data.rows;
this.serverItemsLength = res.data.total_hits;
});
},
},
methods: {},
computed: {
filteredFunderDirectories() {
if (!this.keyword) {
return this.funderDirectories;
}
return this.funderDirectories.filter(
(q) =>
q.funder_name.toLowerCase().indexOf(this.keyword.toLowerCase()) !== -1
);
},
},
};
Ultimately figured it out. added the following to the backend catch
return ctx.send({errorStatus:"Too Many Requests. Please Wait"},429)
And I was able to call

catch separated fails using deferred object

I got this code (using jquery)
function getData(applyFunction, callback) {
$.when(
$.getJSON("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f"),
$.getJSON("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f"),
).done(function(
firstData,
secondData
){
callback(applyFunction, {
firstDataToApply: { data: firstData.popup },
secondDataToApply: { data: secondData.popup }
})
})
}
Is there a way to catch separate errors from the $.getJSON part(or the when part), log those errors, and still be able to send both firstData and secondData(at the same time) to the callback function?
(I'm aware that if some or both $.getJSON fail I'd be sending empty data to the callback, and would have to null check before getting popup)
sorry for the confusing post, thanks in advance
Yes. Promises are pipelines and each handler in the pipeline can transform the value or error passing through, so you can turn a failure into a "success with null" if that's really want you want to do by adding a catch handler and returning null (or whatever value you want to transform the error into) from it. See the catch calls below and also the comments:
function getData(applyFunction, callback) {
$.when(
$.getJSON("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f")
.catch(function(err) {
console.error(err);
return null;
}),
$.getJSON("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f")
.catch(function(err) {
console.error(err);
return null;
})
).done(function(firstData, secondData) {
callback(applyFunction, {
firstDataToApply: {
data: firstData.popup // You'll need checks on this!
},
secondDataToApply: {
data: secondData.popup // And this!
}
});
});
}
Of course, if you're going to do this more than once or twice, you can avoid repeating yourself with a function:
function getJSONOrNull(url) {
return $.getJSON(url).catch(function(err) {
console.error(err);
return null;
});
}
then
function getData(applyFunction, callback) {
$.when(
getJSONOrNull("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f"),
getJSONOrNull("http://www.mocky.io/v2/59d72b5b120000c902cb1b4f")
).done(function(firstData, secondData) {
callback(applyFunction, {
firstDataToApply: {
data: firstData.popup // You'll need checks on this!
},
secondDataToApply: {
data: secondData.popup // And this!
}
});
});
}

Meteor fetch on client undefined outside of helper

I am trying to fetch an entry in a collection with:
client/views/home.js:
criticalCrewNumber = ConfigValues.find({
name: 'criticalCrewNumber'
}).fetch()[0].value;
But I'm getting error:
Uncaught TypeError: Cannot read property 'value' of undefined
If I run the code in the browser console, the desired value is returned as a string.
I have tried various things, e.g. using findOne; placing the code elsewhere in the app; using iron-router waitOn for the subscription to come, etc. Every attempt so far has failed as I end up with undefined.
Here's how the collection is defined, published and subscribed to:
lib/config/admin_config.js:
ConfigValues = new Mongo.Collection("configValues");
ConfigValues.attachSchema(new SimpleSchema({
name: {
type: String,
label: "Name",
max: 200
},
value: {
type: String,
label: "Value",
max: 200
}
}));
both/collections/eventsCollection.js:
if (Meteor.isClient) {
Meteor.subscribe('events');
Meteor.subscribe('config');
};
server/lib/collections.js
```
Meteor.publish('events', function () {
return Events.find();
});
Meteor.publish('config', function () {
return ConfigValues.find();
});
```
Does anyone know what's going on? Thanks.
Consider using ReactiveVar (and Meteor.subscribe callbacks):
criticalCrewNumber = new ReactiveVar();
Meteor.subscribe('config', {
onReady: function () {
var config = ConfigValues.findOne({name: 'criticalCrewNumber'});
if (config) {
criticalCrewNumber.set(config.value);
} else {
console.error('No config value.');
}
},
onStop: function (error) {
if (error) {
console.error(error);
}
}
});

displaying Data from multiple tables with AngularJs

I have been reading different posts with similar questions but I cannot get this figured out. I have a Job class that is linked to different tables such as Customer and Employee. The Data is coming back from the Database but I cannot get the Angular Table to display the linked classes. The suggestions have been to use different mods, restangular, angular-activerecord, ModelCore and this method
angular js model relationships
I am not sure the best route to take and what would be the simplest way of doing it.
app.factory('Job', function ($resource) {
return $resource('/api/apiJob/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('jobFactory', function ($http) {
return {
updateJob: function (job) {
return $http.put('/api/apiJob/' + job.JobId, job);
}
};
});
app.factory('Customer', function ($resource) {
return $resource('/api/apiCustomer/:id',
{ id: '#id' },
{ 'save': { method: 'POST' } },
{ 'update': { method: 'PUT' } },
{ 'query': { method: 'GET', isArray: false } });
});
app.factory('customerFactory', function ($http) {
return {
updateCustomer: function (customer) {
return $http.put('/api/apiCustomer/' + customer.CustomerId, customer);
}
};
});
'use strict';
app.controller('JobCtrl', function ($scope, Job, $resource, $route, jobFactory, notificationFactory, $http) {
////GET Jobs
$scope.jobArray = Job.query()
//New Job Modal
$scope.NewJobModal = function () {
$('#NewJobModal').modal();
}
$scope.submitJob = function () {
var data = {
JobId: $scope.JobId,
JobNumber: $scope.JobNumber,
JobName: $scope.JobName,
CustomerName: $scope.CustomerName,
JobDescription: $scope.JobDescription,
OriginalContract: $scope.OriginalContract,
BillingDate: $scope.BillingDate,
}
$http.post('/api/apiJob/PostNewJob', data).success(function (data, status, headers) {
console.log(data);
});
window.top.location.reload();
};
//End New Job Post
//Delete Job
$scope.deleteJob = function (job) {
Job.delete({ id: job.JobId }, function () {
if ($scope.jobArray.length === 1) {
$scope.jobArray.splice(-1, 2);
} else {
$scope.jobArray.splice(job.JobId - 1, 2);
}
window.top.location.reload();
});
};
//End Delete Job
$scope.updateJob = function (job) {
jobFactory.updateJob(job).success(successCallback).error(errorCallback);
};
$scope.job = [];
var successCallback = function (data, status, headers, config) {
notificationFactory.success();
return $('#editJobModal').modal('hide');
};
var errorCallback = function (data, status, headers, config) {
notificationFactory.error(data.ExceptionMessage);
};
//End Edit Job
}); //End Job Controller
What It looks like in the Browser Console
0: {$id:1, JobId:1, JobNumber:2534, JobName:St.Lukes, JobDescription:Rebuilding Cafeteria,…}
$id: "1"
BalanceDue: 89654123
BalanceToBill: 541256
BillingDate: "2014-08-12T14:43:22.507"
BillingForm: "Invoice"
Budget: 854523658
CertPayroll: true
ChangeOrders: [{$id:4, ChangeOrderId:1, ChangeOrderNumber:7854, ChangeOrderDate:2014-08-12T14:43:22.673,…}]
ContractDate: "2014-08-12T14:43:22.507"
Customers: [{$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}]
0: {$id:2, CustomerId:2, CustomerName:Grove at Wilcrest, CustomerPhoneNumber:8327899667,…}
Employees: [{$id:3, EmployeeId:2, AccountName:Ham Sandwich, EmployeeFirstName:Scott, EmployeeLastName:Willis,…}]
JobAddress: "1234 Mason Rd"
JobCity: "Katy"
JobCost: 784556124
Updated Factory
app.factory('JobGet', function ($http, $q) {
var data = $http({
method: 'GET',
url: '/api/apiJob'
})
return {
query: function () {
var deferred = $q.defer();
setTimeout(function () {
deferred.resolve(data)
}, 2000);
return deferred.promise;
}
};
});
Network Response Tab
[{"$id":"1","JobId":1,"JobNumber":2534,"JobName":"St.Lukes","JobDescription":"Rebuilding Cafeteria","OriginalContract":1250210,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Rudy Sanchez","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814569654,"JobFax":2814563251,"JobHidden":false,"Customers":[{"$id":"2","CustomerId":2,"CustomerName":"Grove at Wilcrest","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"56328 Richmond Ave","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77042,"CustomerWebsite":"grovewilcrest.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":1,"Job":{"$ref":"1"}}],"Employees":[{"$id":"3","EmployeeId":2,"AccountName":"Ham Sandwich","EmployeeFirstName":"Scott","EmployeeLastName":"Willis","EmployeeTitle":"Admin","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"testing#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":1,"Job":{"$ref":"1"}}],"ChangeOrders":[{"$id":"4","ChangeOrderId":1,"ChangeOrderNumber":7854,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":1,"ChangeOrderAttn":"Frank Harvel","ChangeOrderHidden":false,"JobId":1,"Job":{"$ref":"1"}}]},{"$id":"5","JobId":2,"JobNumber":12343,"JobName":"Katy Mills","JobDescription":"New Mall Bathrooms","OriginalContract":32623212,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Mike Hall","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814456965,"JobFax":2814563225,"JobHidden":false,"Customers":[{"$id":"6","CustomerId":1,"CustomerName":"City Center","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"123453 HWY 6","CustomerCity":"Katy","CustomerState":"TX","CustomerZipcode":77493,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":2,"Job":{"$ref":"5"}}],"Employees":[{"$id":"7","EmployeeId":3,"AccountName":"Ice Cream","EmployeeFirstName":"Aaron","EmployeeLastName":"Horstmann","EmployeeTitle":"Office Bitch","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"aaron#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":true,"JobId":2,"Job":{"$ref":"5"}}],"ChangeOrders":[{"$id":"8","ChangeOrderId":2,"ChangeOrderNumber":1823,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"Work Orders","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":2,"ChangeOrderAttn":"Rosie Sanchez","ChangeOrderHidden":false,"JobId":2,"Job":{"$ref":"5"}}]},{"$id":"9","JobId":3,"JobNumber":12398,"JobName":"City Center","JobDescription":"Remodeling Yard House","OriginalContract":56325412,"ContractDate":"2014-08-12T14:43:22.507","BillingDate":"2014-08-12T14:43:22.507","TotalCO":12502105,"RevisedContract":452136852,"Budget":854523658,"BillingForm":"Invoice","TESPM":"Frank Harvel","TESSuperintendent":"Shawn Saulnier","Status":"Active","MoreShit":"More shit goes here","TaxExempt":true,"CertPayroll":true,"JobCost":784556124,"RemainingBudget":96523145,"Profit":854125,"Percentage":45,"TotalBilled":45236554,"BalanceToBill":541256,"PaidToDate":0,"BalanceDue":89654123,"JobAddress":"1234 Mason Rd","JobCity":"Katy","JobState":"TX","JobZipcode":77493,"JobCounty":"Harris","JobPhone":2814256965,"JobFax":2814565325,"JobHidden":false,"Customers":[{"$id":"10","CustomerId":3,"CustomerName":"Twin Peaks","CustomerPhoneNumber":8327899667,"CustomerFaxNumber":7134568547,"CustomerAddress":"8473 Katy Fwy","CustomerCity":"Houston","CustomerState":"TX","CustomerZipcode":77043,"CustomerWebsite":"citycenter.com","CustomerOtherShit":"Other Shit Goes here","CustomerHidden":false,"CustomerPM":null,"CustomerAdmin":"Jane Miller","CustomerAccountant":"Betsy Sue","TESSuperintendent":null,"JobId":3,"Job":{"$ref":"9"}}],"Employees":[{"$id":"11","EmployeeId":1,"AccountName":"Not Sure","EmployeeFirstName":"Frank","EmployeeLastName":"Harvel","EmployeeTitle":"Manager","EmployeeCellPhone":2818567854,"EmployeeOfficePhone":7134527854,"EmployeeEmail":"texas45#gmail.com","CompanyEmployeeId":12521,"EmployeeHidden":false,"EmployeeIsSuper":true,"EmployeeIsPM":false,"JobId":3,"Job":{"$ref":"9"}}],"ChangeOrders":[{"$id":"12","ChangeOrderId":3,"ChangeOrderNumber":45324,"ChangeOrderDate":"2014-08-12T14:43:22.673","ChangeOrderName":"Insert Name Here","ChangeOrderDescription":"It changed again","ChangeOrderAmount":4000,"ChangeOrderApprovedDate":"2014-08-12T14:43:22.673","ChangeOrderApprovedAmount":3000,"ChangeOrderApprovedNumber":3,"ChangeOrderAttn":"Travis Dillard","ChangeOrderHidden":false,"JobId":3,"Job":{"$ref":"9"}}]}]
First of all, this is a work in progress. Your code is very large and to solve this I removed a lot o noise from your plunkr, I left there only what's essential to make it work and only the code involved in it.
Working Demo
First thing to notice, on your JobController you are doing:
////GET Jobs
$scope.jobArray = Job.query();
This worked on previous versions of angular, on the current version there is no automatic promise unwrapping anymore, so you must use the then function:
////GET Jobs
Job.query().then(function(retrievedData){
$scope.jobArray = retrievedData;
});
Notice that on the plunkr I "mocked" the returning of data using $q and a timeout, I actually cleaned the json leaving only the properties that are used on the table, just to make it simpler, you don't need to do that on your code ok? Just keep that part as it is.
Maybe you'll have to modify it just to resolve the promise with the returned data, but this is up to you, the important thing is to return a promise from your query() method and resolve it.
On the HTML I noticed that you are binding the customer name like this:
<td>{{job.Customers.CustomerName}}</td>
But on your Json, the Customers property is an array of customers, so you either return one customer from your api or bind it like this:
<td>{{job.Customers[0].CustomerName}}</td>
I also noticed that there are a lot of jQuery references on your controllers like this:
$('#editJobModal').modal();
This is not recommended and I don't think it will work at all, when dealing with the DOM, always use directives and comunicate with them using bindings, thats the angular way.
Well after all this, my plunkr is showing the table with the 2 fake customers from the Json. Now I suggest you to study that code and apply those principles to your app.
I hope I could help or at least point you at the right direction.

Categories

Resources