Reputation: 11
I’m trying to add an input filed with jQuery ui autocomplete or Twitter Typeahead. I can’t make either work. I get “$(...).typeahead is not a function” or “$(...).autocomplete is not a function” error.
I also tried aurelia-widget from https://github.com/drivesoftware/aurelia-widgets, but I also get “$(...).autocomplete is not a function” error.
I would appreciate if someone could tell me what I am doing wrong.
locate.js
import {customElement, bindable} from 'aurelia-framework';
import $ from 'jquery';
import { autocomplete } from 'jquery-ui';
@customElement('locate')
export class Locate {
@bindable data;
constructor(element) {
this.element = element;
}
activate() {}
detached(){}
attached(){
$(this.element).autocomplete({
source:['Japan', 'USA', 'Canada', 'Mexico']
});
}
}
locate.html
<template>
<label for="locator-input"></label>
<div id="locator-input-wrapper">
<input id="locator-input" type="text" placeholder="Search">
</div>
</template>
Upvotes: 1
Views: 1531
Reputation: 1514
There are several step involved on this. Please let me note the key points
npm install -save jquery jquery-ui
(then and if you are coding on typescript the requested types…)
npm install -save @types/jquery @types/jqueryui
I am installing those packages only for coding with typescript and have intellisense working, but really I will not be using them on runtime.
Then download the built zip minimized version from https://jqueryui.com/ and decompress into that dist directory. Those are the files the we will be really using at runtime.
require.config( { "paths": { "jquery": '../node_modules/jquery/dist/jquery.min', "jquery-ui": '../node_modules/jquery-ui/dist/jquery-ui.min'
(code removed for brevity…)
"shim": { "jquery": { "exports": '$' }, "jquery-ui": { "exports": '$.autocomplete', "deps": ['jquery' ] },
(notice that the line "exports": '$.autocomplete' is not required. Since autocomplete, datepicker, etc. widgets, will be loading onto the $ jQuery global variable, I only used this line only as signaler to my AMD loader the it has really loaded something)
<!DOCTYPE html> <html> <head lang="en"> (code removed for brevity…) <link href="./node_modules/jquery-ui/dist/jquery-ui.min.css" rel="stylesheet" />
i.e. create a class file called: auto-complete.ts (I am coding on typescript, remove types for vainilla javascript).
import { DOM, inject, bindable, bindingMode } from 'aurelia-framework'; import { fireEvent } 'library'; import * as $ from 'jquery'; import 'jquery-ui'; @inject(DOM.Element) export class AutoCompleteCustomAttribute { @bindable source: any; @bindable options = {}; @bindable({ defaultBindingMode: bindingMode.twoWay }) value: JQueryUI.AutocompleteUIParams; private readonly element: Element; constructor(element: Element) { this.element = element; } attached() { $(this.element).autocomplete({ change: (event, ui) => { if (ui.item == null) { $(this.element).val(''); $(this.element).focus(); } }, select: (label, value) => this.value = value, source: this.source }).on('change', e => fireEvent(<any>e.target, 'input')); } detached() { $(this.element).autocomplete('destroy'); } }
i.e. create a class file called: library.ts
export function fireEvent(element: Element, name: string) { var event = createEvent(name); element.dispatchEvent(event); } export function createEvent(name: string) { var event = document.createEvent('Event'); event.initEvent(name, true, true); return event; }
The usage of this custom attribute on your code is just to attach it to a input text tag as follows:
<input auto-complete="source.bind:countries; value.two-way: country">
where countries (string array) and country (string) are properties on your view model.
aurelia.globalResources(["auto-complete"]);
I hope this answer be usefull
Hi again, I am adding an updated code for the custom attribute here below
import { DOM, inject, bindable, bindingMode } from 'aurelia-framework'; import * as $ from 'jquery'; import 'jquery-ui'; import { fireEvent, AutoCompleteSource } from 'libs/library'; @inject(DOM.Element) export class AutoCompleteCustomAttribute { @bindable options = { applyLabel: true, forceMatch: true }; @bindable source: AutoCompleteSource[]; @bindable({ defaultBindingMode: bindingMode.twoWay }) value: number; @bindable({ defaultBindingMode: bindingMode.twoWay }) label: string; private readonly element: JQuery<HTMLElement>; constructor(element: Element) { this.element = $(element); } attached() { this.element .autocomplete({ source: this.source, change: (event, ui) => { if (ui.item == null && this.options.forceMatch) { this.element.val(''); } }, select: (event, ui) => { if (this.options.applyLabel) { event.preventDefault(); this.element.val(ui.item.label); } this.label = ui.item.label; this.value = ui.item.value; }, focus: (event, ui) => { if (this.options.applyLabel) { event.preventDefault(); this.element.val(ui.item.label); } this.label = ui.item.label; this.value = ui.item.value; } }).on('change', e => fireEvent(<any>e.target, 'input')); } detached() { this.element .autocomplete('destroy'); } }
This version funcionality allows us to get the label and the value of the source array when dealing with scenarios where label is the text to search and value is a foreing key.
Added functionality to force the typed text to match one of the existing values. Added funcionality to apply the label instead of value on the input text display.
Custom attribute should be used as follows:
<input type="text" value="${color}" auto-complete="source.bind:colors;value.bind:colorId;label.bind:color">
where colors (array of { "label": string, "value": number }), colorId (number) and color (string) are properties on your view model.
notice also this new type definition added to the library (just simple typescript stuff)
export type AutoCompleteSource = { "label": string, "value": number };
Upvotes: 0
Reputation: 531
I had the same problem with jQuery UI datepicker. So i used jquery-ui-dist instead of jquery-ui when doing NPM install.
import "jquery-ui-dist/jquery-ui";
import "jquery-ui-dist/jquery-ui.min.css";
import "jquery-ui-dist/jquery-ui.theme.min.css";
And then:
$(this.element).datepicker()
Upvotes: 0
Reputation: 3289
I had the same error but when I retrieved jquery-ui using npm it worked. So instead of "jspm install jquery-ui" (which gave me the error) try:
jspm install npm:jquery-ui
package.json
"jquery-ui": "npm:jquery-ui@^1.10.5",
Upvotes: 0
Reputation: 11990
First, you have to be sure about what 'jquery-ui' exports. Does it export something? I believe it exports nothing, instead, it just add some functions to jquery objects. So, you could try this:
import {customElement, bindable} from 'aurelia-framework';
import $ from 'jquery';
import 'jquery-ui';
@customElement('locate')
export class Locate {
@bindable data;
constructor(element) {
this.element = element;
}
activate() {}
detached(){}
attached(){
$(this.element).autocomplete({
source:['Japan', 'USA', 'Canada', 'Mexico']
});
}
}
Upvotes: 1