Closed DarkPetan closed 4 years ago
You can use the (typed) event with an EventEmitter. See the typed event here.
And then on the response, you can go this way (component/service) using an observable:
stuff$ = new EventEmitter<WHATEVER[]>();
stuff = [];
doSomething() {
stuff.push({OBJECT});
stuff$.next(stuff);
}
@zenkkor I tried following the example, but maybe I am too stupid, could you maybe paste a minimum working code? Sorry for the super noobish behaviour. Also the EventEmitter is to be imported from @angular/core
I hope ?
Thanks @zenkkor for your answer. Just needed to add async pipe on ng2-select items property and works fine!
@SadatAnwar what @zenkkor posted is minimum working code, you just need to add [items]="stuff$ | async" in html and that ought to do it.
Ok, just came across issue on this approach. When typing I am getting search results for previous search term. To explain more: let's say I am searching for movies. For instance: Forrest Gump.
Any thoughts? Or is it a known bug?
@DarkPetan I just got the above approach to work, and here is the interesting bit, I guess I did not know it was working because of the exact same issue, I guess what is happening is when you search for some stuff, the list us updated, but you dont see it till you actually close it and open again.
To make that more clear,
@SadatAnwar Yeah, you're right. I did't notice that clicking out and back in updates ng2-select result items. Well, then it's definitely a bug.
@DarkPetan yep. Facing the same issue. Clicking out and then back in updates the ng2-select result items
As mentioned here and numerous other places other people have got this working by manually updating the items using a ViewChild reference. This did not initially work for me but I eventually found a way using a combination of other people's suggestions and a little "tweak" of the ng2-select typescript definition. It's a pretty dirty fix, but until someone fixes this properly it might help you.
As @phil-hutchinson kindly pointed out below, you can skip the whole select.d.ts override by simply casting to any like this:
(<any>this.recipientsInput).open()
Thanks Phil!
I overrode node_modules/ng2-select/select/select.d.ts
changing private open();
to public open(): any;
(see below for how I overrode the ts definition file)
This allows the open
method to be called in your code without raising typescript errors. If I call this after reassigning the items
everything works fine. As I said, pretty dirty but I don't want to fork and fix it properly since there are already a lot of PR's that have never been merged back (including one that attempts to fix this issue from last June).
Here's my solution.
note that I do not assign [items]
to anything
<ng-select #recipientsInput
[multiple]="true"
(typed)="searchUsers($event)">
</ng-select>
note: SelectOption is just a simple class with id: string
and text: string
properties to satisfy ng-select and I've snipped out anything else that wasn't relevant to the problem.
import { Component, Input, Output, EventEmitter, ViewChild, OnInit } from '@angular/core'
import { UserAndOrgSearchService } from '../../../services/userAndOrgSearch.service'
import UserOrgSearchResult from '../../../../types/UserOrgSearchResult'
import SelectOption from '../../../../types/SelectOption'
import { SelectComponent } from 'ng2-select'
@Component({
selector: 'compose-message',
template: require('./compose.component.html'),
styles: [require('./compose.component.scss')],
providers: [UserAndOrgSearchService]
})
export class ComposeMessageComponent implements OnInit {
@ViewChild('recipientsInput') recipientsInput: SelectComponent
private _userOrgSearchString: string = null
constructor(private userAndOrgSearchService: UserAndOrgSearchService) { }
ngOnInit(): void {
this.recipientsInput.items = []
}
searchUsers(searchString: string) {
if (searchString === this._userOrgSearchString) {
// string was deleted so assign empty array to ng-select items
this.recipientsInput.items = []
// force the ng-select to update and show the new list
this.recipientsInput.open()
this._userOrgSearchString = ''
return
}
this._userOrgSearchString = searchString
this.userAndOrgSearchService.search(searchString) // async fetch from server
.then((results: UserOrgSearchResult[]) => {
// map to an array of { id: string, text: string } objects and assign to ng-select items
this.recipientsInput.items = results.map(result => {
return new SelectOption(result.userId, [result.userName, result.organisationName].join(' - '))
})
// force the ng-select to update and show the new list
this.recipientsInput.open()
})
.catch(err => console.log(err))
}
}
If you are looking for a clean way to override the select.d.ts
file without hacking in node_modules or having to fork the code, this worked for me:
tsconfig.json
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"ng2-select": ["ts-overrides/ng2-select.d.ts"]
},
// ...
}
}
ts-overrides/ng2-select.d.ts
export * from 'ng2-select/select/common';
export * from 'ng2-select/select/off-click';
export * from 'ng2-select/select/select.module';
export * from './ng2-select-select';
export * from 'ng2-select/select/select-interfaces';
export * from 'ng2-select/select/select-item';
export * from 'ng2-select/select/select-pipes';
ng2-select-select.d.ts
// ...
export declare class SelectComponent implements OnInit, ControlValueAccessor {
// ...
public open(): any;
// ...
}
// ...
You can then import ng-select into your module and components like this:
app.module.ts
import { SelectModule } from 'ng2-select'
@NgModule({
imports: [
SelectModule
]
})
some.component.ts
import { SelectComponent } from 'ng2-select'
I hope this helps someone! Good luck : )
@JimSangwine the explanation looks really good! (Also I used it for exactly the same use, userOrgSearch! 😆 ) Ill try your your method and report back on how it goes soon...ish
Thanks
this works for me! Thanks bro! :1st_place_medal:
Thanks so much @JimSangwine! We've struggled with this for some time as the other solutions didn't work for us. Finally we have this component working with API calls, wonderful!
You're very welcome folks. Glad it helped :)
@JimSangwine Thanks, this helped a lot me as well. As a note, an easier way to access the private method (rather than the tweak involving tsconfig, overrides, etc.), is to simply cast the object to any:
(<any>this.recipientsInput).open()
Also worthy of note (and thanks), is the _userOrgSearchString
variable, which appears to be used to handle another bug (where the typed() event returns the previous value instead of an empty string when the input is cleared.)
Most welcome Phil, and thanks for the tip!
What is the best way to show message when nothing found?
thank you @JimSangwine this helped me a lot, you're awesome. :)
@JimSangwine Thank you for your souliton, it seems good, but i done the same thing ,and webpack says that 'ERROR in SelectModule is not an NgModule'.
I read that maybe the compiler missing some 'metadata.json' file, and i copied from the node_modules/ng2-select, but its still not work :( Any suggestion?
`ERROR in SelectModule is not an NgModule
ERROR in ./src/overrides/ng2-select.d.ts Module build failed: Error: Debug Failure. False expression: Output generation failed at Object.assert (D:\PROJECTS\EKR\ekr-frontend\node_modules\typescript\lib\typescript.js:3259:23) at Object.transpileModule (D:\PROJECTS\EKR\ekr-frontend\node_modules\typescript\lib\typescript.js:76181:18) at TypeScriptFileRefactor.transpile (D:\PROJECTS\EKR\ekr-frontend\node_modules\@ngtools\webpack\src\refactor.js:161:27) at Promise.resolve.then.then.then (D:\PROJECTS\EKR\ekr-frontend\node_modules\@ngtools\webpack\src\loader.js:324:37) at process._tickCallback (internal/process/next_tick.js:109:7) @ ./src/app/app.module.ts 16:0-42 @ ./src/main.ts @ multi webpack-dev-server/client?https://localhost:4200 ./src/main.ts `
@varrob112 Please see the UPDATE I've added (or @phil-hutchinson 's comment). You don't actually need to override select.d.ts at all.
I hope this helps.
@JimSangwine Thank you very much, it works now.
Thanks,Rob
Sorry @varrob112 , I don't know what that could be. It sounds like a bug with ng2-select though.
Could you show the code for SelectOption
?
I got this working using the examples @JimSangwine provided. Are there any methods or ways to handle "No results" when the async data doesn't return anything?
@JimSangwine Thanks very much for your solution, it works like a charm! :)
New life the component is there: https://github.com/optimistex/ng2-select-ex
@optimistex But the bug with the remote list is still not fixed is it? I replaced the component with yours and still the same behavior... I have problems with both components when changing the ChangeDetectionStrategy to onPush. Now the workaround/hack doesn't work anymore as well.
Does anyone have a solution?
There is a description:
Can someone guide me how should I use that query option to get the results based on what user types in the search box, not just get the data after component initialization (ngOnInit). Tried to use query option with reference to procedure in component but that does not work for me.