I have an application that displays a google map with places autocomplete controller added to it just like this example from google
when an address is searched and selected, or the map bounds are changed I call algolia search, which has an event of onResult, that is fired when it received a response.
I am trying to turn this all into VUE js components. I have managed to get a google maps component and an autocomplete component.
I load the autocomplete first and then have the mounted section of the google maps attach it as a controller.
Where I start to fall down is the interoperability between the components.
I.E on place change which is an autocomplete event. I need to recentre the map and make the search.
But if they are two different components I can't get a reference to the google map.
when I bring the agolia search in to play, that also needs reference to the map when the event fires to pass the marker to it.
I started trying to use a simple view store, but this seems like I am tightly coupling the components.
Have I missed something or are simple stores and global event buses the way to go?
TL;DR;
Vuex may solve your problem, but need to see more code to know what's going on
There are multiple ways of achieving this, but I'll only list two.
Global State Management (Vuex), and props/listeners
Global State Management (Vuex)
If you know you'll only have one instance of each of the components (one map, one autocomplete) this is easy, fast, and reliable solution. The two components do not need to know about each other, they both deal with the global store. The autocomplete will update the data in the store, and the map will be notified whenever the variables it subscribes to change, and update accordingly.
The downside is...
Using vuex makes it harder to reuse and components.. Once you have more than one instance (ie. two autocompletes and two maps) then you may run into some issues, so you'll need to add additional complexity.
Props/Emit
If the two components have a direct connection, either siblings or parent-child relation, using this interaction (IMHO) is preferred.
The autocomplete component can have an #change or even a v-model set up, that parent component would link to the map component using a prop.
It seems like you may be doing it this way, which is not wrong, but without seeing any code, it's hard to make an assessment.
Related
Good day,
I have read through a number of SO posts which were helpful in progressing my problem, but I still have not found anything concrete information on whether there is an established method for the following scenario I face:
I have an application that allows a user to either:
Add a graph; or
Edit an existing graph
When either the 'add graph' button or the 'edit graph' button is clicked, a side-drawer opens. The fields for for the x-axis label, y-axis label and chart title are either blank (for case (1)) or have fields already populated (for case (2)). The fields themselves are editable text input fields.
Currently, when a graph is added, I create a UUID for the graph and then the user can enter text into the fields, and the click save. When save is clicked a Redux action is dispatched to save the content of the fields in the Redux store. The two-way is binding between the text field values and the local state which contains those values initially. Once the 'save' button is clicked and the Redux action fires, the local state is set to empty strings for each field. So Redux is only used when we actually hit the save button.
Now, when an existing graph is selected, I populate the text fields of the side-drawer with the Redux state via mapStateToProps. I use two way binding that is between the text input fields and the Redux store via Redux actions incorporating debouncing to try reduce the number of actions fired off. This means that essentially a slow typer would cause a Redux action to be fired for every key stroke when editing the fields.
I do not like that we have different methods of two-way binding depending on whether the user clicks 'edit' or 'add'. I also do not like having so many Redux actions fired off for something as simple as adding or removing a letter from a word.
I then went through SO and the Redux documents and found that in general people advised that one should not initialise local state with Redux state via props. What I wanted to do was actually copy the Redux state describing the existing content of the fields (when edit is clicked) into the local state and then have the two-way binding in the local state, similar to what I have for the Case (1) scenario. This then eliminates numerous Redux actions being fired off in quick succession and I can use the same two-way binding irrespective of whether 'add' or 'edit' is clicked. But after reading through the documents it seems this is a bad idea for in the case that there is a an unexpected re-render and the local state is reset mid-way through editing, as well as having two sources of truth.
Having the two-way binding in the local state for an added graph and in Redux for an edited graph is quite confusing and does not provide clean and consistent code for those who will need to maintain this code base. Is there a established method that provides for such a scenario? I imagine editing posts on social media would be a similar context to the problem I am facing.
I have not provided my code as it is not a coding question in itself but rather a design problem and my Redux code is split over several files. But I am happy to provide the code if it helps.
First of all, good question. This is a question that comes up quite a bit, especially with how Redux works. Redux has always, in my opinion, forced the question of, "where should this state live?". Now, I know that the docs do give a pretty clear delineation on what state should live in Redux, but when you begin creating an application, it can still be challenging.
For your particular problem, I would choose one or the other - either use local state for both add and edit or use Redux for both add and edit. To have one in Redux and one in local state is, like you said, confusing. Personally, if there is not a lot of data and not a lot of business logic/computational code, I would use local state. It is okay to use state from Redux to set your initial state, i.e., mapStateToProps -> useState() (if you are using hooks). Once you populate your local state from Redux, the only other time that data reaches Redux is when your component is finished working with that data. I would not be worried about "unexpected re-render and the local state is reset mid-way through editing". If that happens, you have a bug that needs to be fixed and that is not the fault of Redux and passing state to the component.
I hope this helps. Please feel free to ask more questions if you would like or need clarification.
I have an application with three main components. Form allows users to select items, Preview shows those items, AppStore is a Mobx store. The button seems to work fine, adding items to the store but the Preview component isn't re-rendering in response to changes. I think this might be because I'm using a higher order component for my drag and drop feature. Does anyone know anything about getting these to work with Mobx?
The project can be found here (the only buttons I've linked up at the moment are 'Banner Image' which adds an item and 'Remove' which should remove it): https://codesandbox.io/s/vnooqvn8yy
I think the issue is that SortableList needs to be passed a regular javascript array, not an observable array.
<SortableList items={AppStore.currentBlocks.slice()} onSortEnd={this.onSortEnd} />
From the mobx docs:
...whenever you need to pass an observable array to an external library, it is a good idea to create a shallow copy before passing it to other libraries or built-in functions (which is good practice anyway) by using array.slice()
I have two components on a page, an update user form and a history of events. They are represented by two reducers (user and events). I want to update the list of events in the store (by calling an API) once once the user has been updated. However, the events should only be updated if the events component is on the page.
What's the best way to achieve this? The only solution I like the idea of is to have a success handler in a parent of the form / event components which dispatches an action which is caught by an effect which will then refresh the list of events. I was hoping this is something I could achieve entirely with effects but I obviously don't know if the component Is on the page and I also need access to route params. Does anyone have any better solutions or can see an issue with this solution?
Typically, the fact that the Events component is shown on the screen represents some sort of part of the "business logic/process" which is likely already represented in the store state. If it is not the case, you seem to need to add it in some way and update it when your events component initializes (ngOnInit) and is destroyed (ngOnDestroy).
Once it is part of the store, you can use it as part of the effect.
The consensus I've found while reading articles about Backbone seems to be: don't store stuff in the view, store it in the model and then have the view listen for changes on the model.
If we're talking about a situation where we already have an obvious model-view pairing this is great. E.g., You have a User model and a UserView view. Obviously you set a model property on the view and it listens to changes on its model.
However, let's say I have a view that shows a list of stuff, and there are a couple of buttons to switch between 'list view' and 'grid view'. This is a very common convention I see in apps and websites. Whether I want 'list view' or 'grid view' isn't really relevant to the models/collections themselves; it seems very specific to the view itself.
At first I just tried using a view exactly like a model: setting a property, binding an event 'change:propertyName', and then using someView.set('propertyName'), etc.. to update it... but this didn't work.
While thinking how to approach this, I thought I remembered seeing something like this before:
var MyView = Backbone.View.extend({
...
model: Backbone.Model(),
...
});
So, unlike having, let's say, a UserModel.. we just have some 'typeless' model. Or I guess, I could actually create a new class, maybe called MyViewModel just for this... although I don't see a reason to.
This allows me to bind to the change event like I had wanted to and set view data with someView.model.set(...).
So my question is: is this a common thing that people do in Backbone for view state? Or is there a better way? Thanks.
Do you want the selected display style (list vs. grid) to be used whenever the user visits the page? If so, the simplest solution might be to store that state in localStorage, and have the view class access it directly.
If you don't need the current display style to be remembered, then maybe you don't need to store the state at all. Have the style change when a button is clicked. When the page refreshes, it returns to the default.
If your app has logged-in users with accounts, and you want their choice to persist across all devices they may be using, you need to have something like a UserModel (which has the logged-in user's info and preferences) that records their choice and saves it to the server. Your view can listen for changes on this model.
The beauty of Backbone (to me) is that there isn't a single right way to do something. These ideas are only some of the ways to can handle it.
You could also have a displayStyle property on the collection. I get this idea from sortable tables: in that case, the sort metadata is part of the collection object. When you resort the table by selecting a column heading, you change the collection's comparator and resort it. The view will be listening for the "sort" event and re-render when it occurs. You could do something similar for display style (you can create your own events by doing this.trigger('display-style') in your collection and having the view listen for that event).
Finally, however you decide to manage that state, you should think about whether this should all be one view class or multiple view classes. I think this would depend a lot on the complexity of your application. In many cases, it might be better to have, say, ProductListView and ProductGridView, instead of a single ProductView with two display styles. Splitting them into separate views might even make it easier to add other styles (ProductImageView, maybe?) in the future.
I'm working on a web app in Google closure where the structure is something like this:
App
+ Control Pane
| + Search Box
| + Search Button
+ Result Pane
+ Results
+ Next Page Link
The actual component structure is quite a bit more complex. The important point is that there are many different components all over the component tree that can initiate certain actions. In this example, hitting enter in Search Box, pressing Search Button, or hitting Next Page all require a query to be made.
This is simple enough to handle. Any child anywhere in the component tree can do
this.dispatchEvent(App.EventType.ACTION, ...)
App will be able to listen to it when the event propagates upwards. The problem is the other direction: When App receives data from its query, it must push it to all children.
It seems very brittle for App to try to push directly to Search box and Results, as their location in the component tree is subject to change. What I'd like to do is fire an App.EventType.DATA_RECEIVED event and have all children (and sub-children, etc.) hear it.
The only way to do this in google closure that I've been able to find is to make a global public singleton instance of App and use as the source for all App.EventType.DATA_RECEIVED events, or to plumb App through to all children and subchildren.
Both of these are messy and brittle in their own way.
Is there a simple way in closure to dispatch events that bubble downwards?
It's not a very satisfactory answer, but it's what I settled on:
There's no good way to communicate such things down the component tree. Even closure itself bumps into this problem, passing opt_domHelper down the tree to every subcomponent.
My suggestion is to subclass goog.ui.Component for your app and create a myapp.Environment class, which contains both opt_domHelper and other environment variables, such as one event listener designated as the application's event channel.
It's not a good solution, per se, but it's the least of all possible evils. And if you've already been dutifully passing opt_domHelper everywhere, then it's no worse a problem: that plumbing becomes more extensible, and the opt_domHelper itself is hidden from implementors (who now pass around environment instead).