The general idea of nswag software is amazing.
The guys have totally ruined it though.
I'm really now thinking of dropping it for the following reasons:
overcomplicated
problematic
extremely poorly documented
unpopular
Regarding my version - "nswag#11.17.19".
My service is supposed to pass a compound structure (e.g. nested arrays) - but in recent versions it passes all of the content via the URL and here's what I mean:
Moreover, recent versions of it don't generate input classes - e.g. my API controller has action ImportEntries(ImportEntriesInput input)
nswag no longer generates input class (I mean ImportEntriesInput) - instead it just lists all of its members:
For example compare
importEntries(input: ImportEntriesInput | null | undefined): Observable<VocabularyDto> {
with
importEntries(entries: CrawlerEntryDto[] | null | undefined, vocabularyId: number | undefined, newVocabulary: boolean | undefined, typeId: number | undefined, name: string | null | undefined, notes: string | null | undefined): Observable<VocabularyDto | null> {
Maybe the guys who develop it find it okay, but I'd say this totally overcomplicates the whole approach and is too bad.
I wasn't really able to find documentation covering this part.
Anyone knows how to solve this?
Also, here's the bit where it creates the content being passes in URL:
importEntries(entries: CrawlerEntryDto[] | null | undefined, vocabularyId: number | undefined, newVocabulary: boolean | undefined, typeId: number | undefined, name: string | null | undefined, notes: string | null | undefined): Observable<VocabularyDto | null> {
let url_ = this.baseUrl + "/api/Import/ImportEntries?";
if (entries !== undefined)
entries && entries.forEach((item, index) => {
for (let attr in item)
url_ += "entries[" + index + "]." + attr + "=" + encodeURIComponent("" + item[attr]) + "&";
});
if (vocabularyId === null)
throw new Error("The parameter 'vocabularyId' cannot be null.");
else if (vocabularyId !== undefined)
url_ += "vocabularyId=" + encodeURIComponent("" + vocabularyId) + "&";
if (newVocabulary === null)
throw new Error("The parameter 'newVocabulary' cannot be null.");
else if (newVocabulary !== undefined)
url_ += "newVocabulary=" + encodeURIComponent("" + newVocabulary) + "&";
if (typeId === null)
throw new Error("The parameter 'typeId' cannot be null.");
else if (typeId !== undefined)
url_ += "typeId=" + encodeURIComponent("" + typeId) + "&";
if (name !== undefined)
url_ += "name=" + encodeURIComponent("" + name) + "&";
if (notes !== undefined)
url_ += "notes=" + encodeURIComponent("" + notes) + "&";
url_ = url_.replace(/[?&]$/, "");
let options_ : any = {
observe: "response",
responseType: "blob",
headers: new HttpHeaders({
"Content-Type": "application/json",
"Accept": "application/json",
'Authorization': 'Bearer ' + localStorage.getItem('token')
})
};
return this.http.request("post", url_, options_).flatMap((response_ : any) => {
return this.processImportEntries(response_);
}).catch((response_: any) => {
if (response_ instanceof HttpResponseBase) {
try {
return this.processImportEntries(<any>response_);
} catch (e) {
return <Observable<VocabularyDto | null>><any>Observable.throw(e);
}
} else
return <Observable<VocabularyDto | null>><any>Observable.throw(response_);
});
}
Quite appalling, isn't it?
swaggerToTypeScriptClient bit from config:
"codeGenerators": {
"swaggerToTypeScriptClient": {
"className": "{controller}ServiceProxy",
"moduleName": "",
"namespace": "",
"typeScriptVersion": 2.0,
"template": "Angular",
"promiseType": "Promise",
"httpClass": "HttpClient",
"dateTimeType": "MomentJS",
"nullValue": "Undefined",
"generateClientClasses": true,
"generateClientInterfaces": false,
"generateOptionalParameters": false,
"wrapDtoExceptions": false,
"wrapResponses": false,
"generateResponseClasses": true,
"responseClass": "SwaggerResponse",
"useTransformOptionsMethod": false,
"useTransformResultMethod": false,
"generateDtoTypes": true,
"operationGenerationMode": "MultipleClientsFromPathSegments"
"markOptionalProperties": false,
"generateCloneMethod": true,
"typeStyle": "Class",
"extensionCode": "service.extensions.ts",
"generateDefaultValues": true,
"excludedTypeNames": [],
"handleReferences": false,
"generateConstructorInterface": true,
"importRequiredTypes": true,
"useGetBaseUrlMethod": false,
"baseUrlTokenName": "API_BASE_URL",
"injectionTokenType": "InjectionToken",
"output": "../src/shared/service-proxies/service-proxies.ts"
},
This fixes the issue with URL mentioned in my post above.
That wasn't documented, but in order for nswag to work properly with ASP.NET Core you are meant to apply [FromBody] attribute to every action accepting data
e.g.
public async Task<VocabularyDto> ImportEntries([FromBody] ImportEntriesInput input)
Related
I am working on our Application-integration inside Zapier and using zapier's built in methods for polling data. The script is now long and use a lot of repetitive function objects. How can I use prototype inheritance model for each attribute call so that I can reuse it for similar calls for other attributes? A typical api call is as follows:
var Zap = {
myattribute_post_poll: function(bundle) {
var results = JSON.parse(bundle.response.content);
results.value.reverse();
//attribute call
var cRequest = {
'url': "myURL.com/a/" + bundle.auth_fields.tenant_id +
"/odata/standard.odata/Catalog_attibute(guid'" + results.value[i].attribute_Key + "')?$format=json",
'headers': {
"Authorization": "Basic " + btoa(bundle.auth_fields.username + ':' + bundle.auth_fields.password)
},
'method': "GET"
};
var cResponse = z.request(cRequest);
try{
var JSONResponse = JSON.parse(cResponse.content);
results.value[i].Customer_name = JSONResponse.Description;
} catch(error){
console.log(error);
results.value[i].Customer_name = results.value[i].Company_Key;
}
return results;
}
The best technique is just to break into reusable properties on Zap:
var Zap = {
reusable_thing: function(arg) {
return arg + 1;
},
attr_pre_poll: function(bundle) {
bundle.request.params = Zap.reusable_thing(1);
return bundle.request;
}
};
This might be helpful to others, so adding my prototype object here:
var Zap = {
attrGuidRequest : function(obj, document, key){
var attrResponse = JSON.parse(
z.request({
'url': "myUrl" + tenant_id +
"/odata/.." + document + "(guid'" + key + "')?$format=json",
'headers': {
"Authorization": "Basic " + btoa(username + ':' + password)
},
'method': "GET"
}).content) || {};
return attrResponse;
}
}
I am trying to use more than 10000 datas in my combobox and I have this code
$.fn.select2.amd.define('select2/data/customAdapter',[
'select2/data/array',
'select2/utils'
],
function (ArrayAdapter, Utils) {
function CustomDataAdapter ($element, options) {
CustomDataAdapter.__super__.constructor.call(this, $element, options);
}
Utils.Extend(CustomDataAdapter, ArrayAdapter);
CustomDataAdapter.prototype.query = function (params,callback) {
console.log(params);
var pageSize,
results;
pageSize = 20;
results = _.filter(content, function (e) {
return (params.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0);
});
console.log(results);
callback({
results: results.slice((params.page - 1) * pageSize, params.page * pageSize),
// retrieve more when user hits bottom
more : results.length >= params.page * pageSize
});
};
return CustomDataAdapter;
}
);
var customAdapter=$.fn.select2.amd.require('select2/data/customAdapter');
objCmb.select2({
allowClear: true,
disabled: dis,
placeholder: Empty,
data: content,
formatLoadMore : 'Loading more...',
dataAdapter:customAdapter
});
when I use the select2 this error appear
TypeError: params.term is undefined
...ms.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0)
The problem is that when someone focuses the select2 control, there's no really a term, so the params object is empty (e.g. {}). You can see this in this JsFiddle (just try to search for something).
If you want to get rid of that error, you can modify your custom query function to account for that:
CustomDataAdapter.prototype.query = function (params, callback) {
var pageSize, results;
pageSize = 20;
results = _.filter(content, function (e) {
return (params.term == null || params.term === "" || e.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0);
// ^^^^^^^^^^^^^^^^^^^
});
callback({
results: results.slice((params.page - 1) * pageSize, params.page * pageSize),
more: results.length >= params.page * pageSize
});
};
This will be working as you'd expect it to (modified fiddle).
I would also like to note that your code example does not include the select population with items, so it's not present in the above fiddles either.
Select2 Jquery Plugin
I was having hard time how to override the default message for minimum length input in jquery Select2.
by default the plugin gives the following message.
Default Text
Please enter 1 more characters
My requirement was to show, the following text
Required Text
Enter 1 Character
please share the solution.
Thanks.
The accepted answer does not work for Select2 v4. Expanding on the comment by #IsaacKleinman, the way to override the default messages for an individual Select2 instance is through the language property:
var opts = {
language: {
inputTooShort: function(args) {
// args.minimum is the minimum required length
// args.input is the user-typed text
return "Type more stuff";
},
inputTooLong: function(args) {
// args.maximum is the maximum allowed length
// args.input is the user-typed text
return "You typed too much";
},
errorLoading: function() {
return "Error loading results";
},
loadingMore: function() {
return "Loading more results";
},
noResults: function() {
return "No results found";
},
searching: function() {
return "Searching...";
},
maximumSelected: function(args) {
// args.maximum is the maximum number of items the user may select
return "Error loading results";
}
}
};
$('#mySelect').select2(opts);
To override the functions globally, call the set function on the defaults (according to the docs):
$.fn.select2.defaults.set("key", "value")
However, in our code we do it like this:
$.fn.select2.defaults.defaults['language'].searching = function(){
return 'Custom searching message'
};
I don't know why we don't follow the docs, but it works.
Solution
Here is the solution that i have found out.
Prior to v4
Initialize
$("input[name='cont_responsible'],input[name='corr_responsible'],input[name='prev_responsible'],input[name='pfmea_responsible']").select2({
minimumInputLength: 1,
formatInputTooShort: function () {
return "Enter 1 Character";
},
});
Note
Do not forget to add this code in your document. ready function.
$(document).ready(function () {
});
I shared my solution, any better solutions are welcome.
Thanks.
Using v4 and onwards
The following worked for V4. #Isaac Kleinman
language: { inputTooShort: function () { return ''; } },
You can try this on version 4.0 or higher
you can see reference for answer frome this link :
issues reference
$("#select2").select2({
minimumInputLength: 1,
language: {
inputTooShort: function() {
return 'Please Add More Text';
}
}
});
If you are using django-select2, just add attributes to your form in forms.py:
widget=BookSelect2Widget(
attrs={'data-minimum-input-length': 1}
)
Override the function behaviour like below
$.fn.select2.defaults = $.extend($.fn.select2.defaults, {
formatMatches: function(matches) {
return matches + $filter('translate')('label.matches.found');
},
formatNoMatches: function() {
return $filter('translate')('noMatches.found');
},
formatInputTooShort: function(input, min) {
var n = min - input.length;
return $filter('translate')('label.please.enter ') + n + $filter('translate')(' more.characters') + (n == 1 ? "" : "s");
},
formatInputTooLong: function(input, max) {
var n = input.length - max;
return $filter('translate')('please.delete ') + n + $filter('translate')('')('delete.characters') + (n == 1 ? "" : "s");
},
formatSelectionTooBig: function(limit) {
return $filter('translate')('select.only') + limit + $filter('translate')('select.item ') + (limit == 1 ? "" : "s");
},
formatLoadMore: function(pageNumber) {
return $filter('translate')('load.results');
},
formatSearching: function() {
return $filter('translate')('label.search');
}
});
}
I have an issue with Breezejs (1.4.2) q (0.9.7)
I want to add a computed property for an entity.
var doctorInitializer = function (doctor) {
doctor.FullName = ko.computed(function () {
return doctor.FirstName() + " " + doctor.MiddleName() + " " + doctor.LastName() + " " + doctor.SurName();
});
};
var doctorName = '/breeze/polyclinic',
doctorManager = new breeze.EntityManager(doctorName);
var store = doctorManager.metadataStore;
store.registerEntityTypeCtor("Doctor", null, doctorInitializer);
i try adding a knockout computed to the constructor
var doctor = function () {
self.FullName = ko.computed( {
read: function() {
return self.FirstName + " " + self.MiddleName + " " + self.LastName + " " + self.SurName;
},
deferEvaluation: true
});
};
store.registerEntityTypeCtor("Doctor", doctorInitializer);
in both cases only work if i remove the parenthesis but MiddleName and SurName is not required and instead of empty string i got null
this is the error i have http://screencast.com/t/bP9Xnmf9Jm
UPDATE
I try adding the error on console log and follow your example and i have the same error is not a function http://screencast.com/t/bQTyV8XGD0Pk
doctor.FullName = ko.computed(function () {
var fullName = "";
fullName += doctor.FirstName();
if (doctor.FirstName()) {
fullName += ' ' + doctor.FirstName();
}
fullName += ' ' + doctor.LastName();
if (doctor.SurName()) {
fullName += ' ' + doctor.SurName();
}
return fullName;
});
var query = breeze.EntityQuery.from("Doctors").orderBy("Id")
doctorManager.executeQuery(query)
.then(function (data) {
self.doctors.removeAll();
self.doctors(data.results);
})
.fail(function(error) {
console.log(error);
});
I hope someone can help me
The error you are seeing in the screenshot is because your query is throwing an error that you are not handling. Attach a .fail(failFunction) on the end of your entityQuery.
You can't call doctor.Surname() if there is no Surname function that is attached. Calling doctor.Surname just returns a function that doesn't give you a value.
Odds are, you don't 100% get why it's not working because you don't understand how Knockout works. You probably don't yet understand the meaning of what I am describing above either. You need to understand how Knockout works first, then try to learn Breeze.
If you want to just make it work without understand how or why put this in there and continue on. This assumes that there is a property returned called MiddleName and SurName that are just empty.
doctor.FullName = ko.computed(function () {
var fullName = "";
fullName += doctor.FirstName();
if (doctor.MiddleName()) { fullName += ' ' + doctor.MiddleName(); }
fullName += ' ' + doctor.LastName();
if (doctor.SurName()) { fullName += ' ' + doctor.SurName(); }
return fullName
});
I'm having a problem calling the save method on a domain object. The error is:
groovy.lang.MissingMethodException: No signature of method: static my.awesome.Class.FeedHit.save() is applicable for argument types: () values: []
Possible solutions: save(), save(java.lang.Boolean), save(java.util.Map), wait(), any(), wait(long)
I'm going through an array of FeedHits, updating a flag, and then calling the save method:
void updateFeedHits(Set<FeedHit> list, FeedHitStatus status) {
for (FeedHit feedHit: list) {
feedHit.status = status
try {
feedHit.save()
} catch (Exception ex) {
log.info("unknown exception during update FeedHit", ex)
}
}
}
I've seen other StackOVerflow users have the same problem, but only during tests. This code is in normal release code.
Any help would be appreciated.
EDIT:
Here is the FeedHit object, slightly edited.
class FeedHit {
Feed feed
String title
String body
String url
FeedHitStatus status
String sourceId
String hash
Date publishedDate
Date dateCreated = new Date()
Integer pos = -1
static constraints = {
alert(nullable: true)
title(nullable: true)
body(nullable: true)
url(nullable: true)
status(nullable: true)
sourceId(nullable: true)
hash(nullable: true)
pos(nullable: true)
publishedDate(nullable: true)
dateCreated(nullable: true)
}
static mapping = {
table('alert_hit')
autoTimestamp false
version(false)
alert(column: 'alert_id')
body(sqlType: 'text')
url(sqlType: 'text')
sourceId(column: 'sourceId')
publishedDate(column: 'publishedDate')
dateCreated(column: 'dateCreated')
}
/**
* Generates a hash from title, body and url.
*/
public AlertHit generateHash() {
StringBuffer sb = new StringBuffer();
if (this.title != null) {
sb.append(this.title);
}
if (this.body != null) {
sb.append(this.body);
}
if (this.url != null) {
sb.append(this.url);
}
if (this.publishedDate != null) {
sb.append(this.publishedDate.getTime());
}
if (sb.length() > 0) {
hash = Md5Hash.hash(sb.toString());
}
this
}
#Override
public String toString() {
return "AlertHit{" +
"id=" + id +
", alert=" + alert +
", title='" + title + '\'' +
", body='" + body + '\'' +
", url='" + url + '\'' +
", status=" + status +
", sourceId='" + sourceId + '\'' +
", hash='" + hash + '\'' +
", publishedDate=" + publishedDate +
", dateCreated=" + dateCreated +
", pos=" + pos +
", version=" + version +
'}';
}
}
You need to annotate GORM functions, if you want to use domain class outside grails. See http://www.rimerosolutions.com/using-gorm-standalone-outside-grails/
I would recommend you to use another way than native threads. Try: Quartz-Plugin