@@ -121,4 +121,124 @@ Example below can give you an idea how to create component for Mapbox GL JS plug
121121
122122** [ VueMaboxGeocoder] ( https://github.com/soal/vue-mapbox-geocoder ) — wrapper for [ mapbox-gl-geocoder] ( https://github.com/mapbox/mapbox-gl-geocoder ) ** :
123123
124+ ``` js
125+ // First, there is no separate HTML to render, so we don't need template and SFC, so it's just JS file
126+
127+ import MapboxGeocoder from " @mapbox/mapbox-gl-geocoder" ;
128+ import { $helpers } from " vue-mapbox" ; // Get $helpers from VueMapbox
129+
130+ // Define list of mapbox-gl-geocoder events
131+ const geocoderEvents = {
132+ clear: " clear" ,
133+ loading: " loading" ,
134+ results: " results" ,
135+ result: " result" ,
136+ error: " error"
137+ };
138+
139+ export default {
140+ name: " GeocoderControl" ,
141+ mixins: [$helpers .asControl ], // MapboxGeocoder is a control, so we use mixin
142+
143+ inject: [" mapbox" , " map" ], // Here we inject objects provided by MglMap
144+
145+ props: {
146+ // MapboxGeocoder requires access token
147+ accessToken: {
148+ type: String ,
149+ required: true
150+ },
151+ input: {
152+ type: String ,
153+ default: null
154+ },
155+ proximity: {
156+ type: Object ,
157+ default: null
158+ }
159+ // ...here goes other props...
160+ },
161+
162+ data () {
163+ return {
164+ initial: true
165+ };
166+ },
167+
168+ // Here we watch for props and and apply changes to MapboxGeocoder if needed
169+ watch: {
170+ input: {
171+ handler (next , prev ) {
172+ if (this .control && next !== prev) {
173+ this .control .setInput (next);
174+ }
175+ },
176+ immediate: true
177+ },
178+ proximity (next , prev ) {
179+ if (this .control && next !== prev) {
180+ this .control .setProximity (next);
181+ }
182+ }
183+ },
184+
185+ created () {
186+ this .control = null ; // Here we will store MapboxGeocoder instance. We don't want Vue reactivity system mess with it, so we store it non-reactive
187+ if (this .accessToken && ! this .mapbox .accessToken ) {
188+ this .mapbox .accessToken = this .accessToken ;
189+ }
190+ this .control = new MapboxGeocoder (this .$props ); // Creating MapboxGeocoder instance and pass props as options to it
191+ this .control .on (" results" , this .$_updateInput ); // We need to update synchronized prop "input" when user enters some query to search field
192+
193+ // Now we can add control to the map
194+ this .$_deferredMount ();
195+ },
196+
197+ beforeDestroy () {
198+ this .control .off (" results" , this .$_updateInput );
199+ // Also, control will be removed from map in beforeDestroy() lifecycle hook in `asControl` mixin
200+ },
201+
202+ methods: {
203+ $_deferredMount () {
204+ // Because this component placed in MglMap sub-tree, map already initialized and injected above
205+ this .map .addControl (this .control );
206+ if (this .input ) {
207+ // Set input in MapboxGeocoder if there is default data
208+ this .control .setInput (this .input );
209+ }
210+ // Emit added event. `$_emitEvent` method is came from `asControl` mixin
211+ this .$_emitEvent (" added" , { geocoder: this .control });
212+ this .$_bindSelfEvents (Object .keys (geocoderEvents)); // Bin events to emit them as Vue events
213+ this .initial = false ; // Initialization done
214+ },
215+
216+ $_bindSelfEvents (events) {
217+ // $_bindSelfEvents is provided by `asControl` mixin. but we need to replace it because MapboxGeocoder do not follow Mapbox Gl JS events schema and we need custom processing for them
218+ const vm = this ;
219+ // Here we use this.$listeners to subscribe only on events that user listens on component
220+ Object .keys (this .$listeners ).forEach (eventName => {
221+ if (events .includes (eventName)) {
222+ this .control .on (eventName, vm .$_emitControlEvent .bind (vm, eventName));
223+ }
224+ });
225+ },
226+
227+ // Process event to line up with VueMapbox events format
228+ $_emitControlEvent (eventName, eventData) {
229+ return this .$_emitSelfEvent ({ type: eventName }, eventData);
230+ },
231+
232+ $_updateInput (results) {
233+ if (! this .initial ) {
234+ const input = results .query ? results .query .join (" " ) : " " ;
235+ this .$emit (" update:input" , input); // update synchormized prop "input"
236+ }
237+ }
238+
239+ // ...here goes other public methods
240+ }
241+ };
242+ ```
243+
124244<!-- ## Component API recommendations -->
0 commit comments