I have a custom class in Angular4 to manage a map (angular component as well). My class has a template inside which i have ngui-map element (imported from the library below). I have been able to bind to events triggered by this element (such as map move, map click etc.).
The questions is: is it possible to access this map object from my typescript code? I need to access the map's properties inside some button click, but I just cant figure out how.
The only solution I have been able to come up with is to hook up event handler for the map move and keep storing the current map location (which are sent as event args) inside some helper variables and then use those variables, but surely there is another better way?
I am new to angular so sorry if this question is a bit basic or doesnt make any sense. I ve tried googling but I cant seem to word the query correctly to get relevant results.
ngui-map
https://github.com/ng2-ui/map
If you have a component that implements this map, you can use a template variable to call the methods of the component in the template.
For example:
<map-component #map></map-component>
<button type="button" class="btn btn-default" (click)="onClick(map.getCoordinates())></button>
This is assuming your MapComponent has public methods that allow you to get the information you need.
Related
Let's say I have a SearchForm Component that has a Reset button, as well as a slot to include any desired SearchField Components. When I click SearchForm's Reset button, I'd like to call each SearchField's reset method, but I'm having a hard time understanding how to do this dynamically... I obviously don't want to add refs to each SearchField because these aren't static and can change when using the SearchForm in some other part of the application. Fiddle for example.
In Vue2, it seemed liked there was some sort of $children property, but that was taken out in Vue3. I was thinking I could potentially use querySelectorAll to access all "input" elements, but I didn't see how I could access the DOM element's component instance (similar to jQuery's $ selector). If I access the $slots.default() and loop over it, I get some weird object that isn't a component instance... or rather, it doesn't have the typical properties that the component instance has, and I have no clue how to access the actual instance from here.
It's also possible I'm not thinking in a Vue-centric way, as I'm new to the framework, so how can I solve this issue?
I've come up with this solution, but I don't like it, as it adds some minor coupling. Basically, I listen for when the field is created, check its parent, and if it's a form, I push it onto the array of children. Then when the parent's reset is called, it loops through its children. This is a fragile approach because it requires the direct parent to be the form... if the field was nested inside of another component, it won't be added to the form's fields. I'm also pretty sure this breaks the best practices of the framework. It's a shame there doesn't appear to be a way of accessing child instances (without being forced to use ref)... that seems like it'd be desired by a lot of devs.
I came up with yet another way, but once again, seems a little shady because I'm accessing the DOM element's private property __vueParentComponent. I like it better than the previous answer because it's not coupled, and I can use getElementsByTagName. Fiddle for reference. This is the relevant code that I added as a method in SearchForm:
getFields() {
const fields = this.$el.getElementsByTagName("input");
// getElementsByTagName returns an HTMLCollection, which doesn't have map,
// so let's use spread to make an array and use map
return [...fields].map((fieldEl) => {
return fieldEl.__vueParentComponent.proxy;
});
}
Last solution... this one seems to be more stable and the proper Vue way. You use provide/inject; the parent provides the value, and the child injects it, so it can use it. Vuetify does something similar, but they have their own register and unregister methods, which I've created in the Fiddle but as a rudimentary implementation. The only caveat being if you're using TypeScript, the inject won't work properly, and you'll have to use one of these solutions.
I'm pretty new to angular, but I have managed to get most of the concepts down. However, I can't seem to figure out how I should go about solving my issue.
I have one component, that has other components as its children. I want to be able to loop through the child components, and add data to them separately, either before they are rendered, or after they are rendered.
The master component is an HTML version of a government form, and I have scattered throughout it a simple component that is supposed to display text from a database relevant to the field it is in.
If I was using something like jQuery, I would just attach an id to each component, and loop through them, adding data if the component id matches the key of the JSON object.
Is there any standard way to do something like this with angular?
You'd be better off "binding" any information you'd like to provide to your child components instead of implementing a vanilla/jQuery solution that involves querying the DOM and then manually manipulating the DOM.
Take a look at property-binding and two-way binding.
Here's a quick example:
<my-child-component [someProperty]="myValue"></my-child-component>
<my-menu-component [menu]="menuData"></my-menu-component>
You probably should rethink the way you are trying to do it, when you start with Angular you need to leave a lot of concept that you learnt in jQuery behind.
We don't manipulate the DOM directly in Angular, we manipulate the data that is bound to the template and that binding is what updates the DOM.
Tom added an answer as I was typing, he is saying what I was going to.
The angular way to achieve what you want is to use one-way data binding. Check out the example in the documentation.
In the example they have a child component in the template html of the app.
<bank-account bankName="RBC" account-id="4747"></bank-account>
You can one-way bind data by referencing a public property on the parent and using the square bracket syntax to indicate one-way binding like so:
<bank-account [bankName]="somePropertyOnTheParent" [account-id]="someOtherPropertyOnTheParent"></bank-account>
I'm trying to give to the user the ability to create, drag and connect multiple nodes but I still don't understand how angular render this or the life cycle of components and other, so even after a lot of research, I'm still unable to figure out how to fix the issues listed below.
Basically, I'm to trying to achieve what I already achieved with a simple HTML page, but this time here with Angular and angular is not making it easy for me.
First I was struggling with making the new divs draggable, I managed to do that but now the endpoints do not seem to be able to connect, don't know why or how to fix it.
And even after checking out the doc I still don't understand how stuff in the code like AfterViewInit, ComponentFactoryResolver, parentInjector, resolveComponentFactory work, indeed they solved the draggability issue for me, but don't know why or how they fixed it.
So any help or explanation would reaaaaally appreciated.
The thing is that you are adding endpoints and making nodes draggable using new jsplumb instance created at the moment where that node component is created,
which will result eventually in many jsplumb instances for every node, and that's what seems to be the problem cuz apparently to connect those nodes they must be initialized with the same jsplumb instance : So try creating just one instance (or use the default jsplumb instance) in the parent component (the one holding all the nodes) and then pass it with property binding (#input...) to the newly created nodes to use to become draggable etc.
First I want to be clear why I don't want to use Event Bus in this situation: Because Event Bus won't work for this situation!
Please see the simplified structure of my Vue.js Project first:
App.vue
|---Map.vue
|---Info.vue
| |---layerInfo.vue
|
|---WMS.vue
|---WFS.vue
|---Basic.vue
The diagram only shows which component creates which child component, but they are not all created at the start of the Vue app. The layerInfo.vue will only be created when some conditions are filled (You can image only after the use click the button, the layerInfo.vue will be rendered/created)
What have I done:
In Map.vue component, I have created a Object map, which contains the useful information, and I $emit the map to a Global Event Bus.
The Problem is, at this momente, the layerinfo.vue doesn't exist. So I can't listen to the $emit event use $on. (Even I tried, I didn't get the map)
And a further question about Event Bus: I used Event Bus in my other part of the vue app. But I am still confused, if the Event Bus makes a two-way-data-binding or only one-way?
My conclusion: global Event Bus can only be userd to pass data between two non-related components when they both exist.
But my question is: how I can then pass date between two non-related components when I don't know when the one that needs to receive the data will be created / rendered?
I am using things like:
var MUSIC = React.renderComponent( Music({ }), document.getElementById("music-div"))
to later in the script, in an independent element (so not parent of MUSIC) do:
MUSIC.setProps({ url: 'http://...' })
to send a song to de music player, which is detached from the rest, so it does not accidentally gets refreshed by react, because it was programmatically generated (wavesurferjs)
Fine, however, the recent few updates (.11.x) have apparently deprecated that. I do understand where they are coming from, it fits the whole React logic.
However, how will we now ever programmatically modify state/props from outside? Even when I want to talk directly to the parent, which should be allowed.
The changelog tells me in this case the MUSIC variable would have become a descriptor, however, in consoles out the exact same object as far as I can tell. And the documentation says nothing about this descriptor and even less about alternative possibilities.
(http://facebook.github.io/react/blog/2014/07/17/react-v0.11.html#descriptors)
So, if I have two divs
<div id="main-div"> <button></button></div>
<div id="music-div"> </div>
And want to keep them separate, how would I go about giving two parallel parents each-other props?
I don't want to put both in one react div, which would not even solve my problem, because, how would the button in main-div give the props to music-div?
Or would their conceived alternative be to just create a new instance on that id and hope it diffs to 0?
The update states:
"You could store that reference and then call functions on it (eg
component.setProps(...)). This no longer works."
However, that still does work, with (0.11.1) so I don't understand what they are talking about?
You've got several options.
Wrap both main-div and music-div with an "Application" component. Pass a handler down that changes its state so the div's are re-rendered.
Use an event bus to dispatch and listen to events. Basically a component exposes its private setState/setProps() methods to the event bus in a listener. The other component dispatches an event that triggers that listener.