Initialize dynamic Component in Code using Vue.js - vue.js

I am currently developing a web application that is used to display elements for events on a map provided by HERE Maps. I am using Vue.
I have some components, but the relevant component is the component HereMaps.vue which initializes the map using the HERE Maps Api.
The HERE Maps Api provides the possibility to place so called InfoBubbles on the map showing additional information. These InfoBubbles can be provided some HTML-code in order to customize their appearance.
Please refer to the documentation for additional information
Following the documentation the code looks something like this:
let bubble = new H.ui.InfoBubble(marker.getPosition(), {
content: "<div class='someClass'>Some Content</div>"
});
this.ui.addBubble(bubble)
This is happening after mount in the "mounted" method from Vue in the "HereMaps" component.
The Bubbles are added in a "closed" (hidden) form and dynamically "opened" to reveal their content when the corresponding marker icon on the map is clicked. Therefore the HTML-code is present on the DOM after the component is mounted and is not removed at a later stage.
Now instead of supplying custom code within each bubble added to the UI i want to just add a component like this:
let bubble = new H.ui.InfoBubble(marker.getPosition(), {
content: "<myDynamicComponent></myDynamicComponent>"
});
this.ui.addBubble(bubble)
It does not matter to me wether the component is initialized using props or if it is conditionally rendered depending on the state of a global variable. I just want to be able to use the "myDynamicComponent" in order to customize the appearance in a different file. Otherwise the design process gets very messy.
As far as i know this is not possible or at least i was not able to get it work. This is probably due to the fact that the "myDynamicComponent" is not used within the "template" of the "HereMaps" component und thus Vue does not know that it needs to render something here after the directive is added to the DOM in the "mounted" method.
This is what the InfoBubble looks using normal HTML as an argument:
This is what the InfoBubble looks using the component as an argument:
It appears to just be empty. No content of the "myDynamicComponent" is shown.
Does anyone have any idea how i could solve this problem.
Thank You.

Answer is a bit complicated and I bet you wouldn't like it:)
content param can accept String or Node value. So you can make new Vue with rendered your component and pass root element as content param.
BTW, Vue does not work as you think, <myDynamicComponent></myDynamicComponent> bindings, etc exists in HTML only in compile time. After that all custom elements(components) are compiled to render functions. So you can't use your components in that way.
Give us fiddle with your problem, so we can provide working example:)

Related

How to render markup so there's less FLOUT with a Vue Component?

I need to render a list of items (server rendered), each item has a countdown timer. When I just have my view component in each dom element there's nothing there, then POP, the view component renders the countdown... Now I know this value on the server side as well, is there some way to render it immediately such that the vue component will takeover the rendering? (Does that make sense)
Like the html from the server renders 50:32 (minutes, seconds), but then the view component takes over, removes it and starts the countdown 50:31, 50:30... etc etc.
I've tried passing the server val in as a prop and just rendering it inside the node, still pops (I assume because the component is rendering...)
Is this even doable, or am I stuck with a loader?
Thank you for your relevant question, I propose an answer from what I understand.
you are trying to dynamically pass a property from the server to a view instance already created. This is not possible because Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it’s possible to add reactive properties to a nested object using the
Vue.set(object, propertyName, value) method:
Vue.set(vm.someObject, 'b', 2)
go on the official documentation of Vue to know more
here : https://v2.vuejs.org/v2/guide/reactivity.html
hope that it puts you on the right track

Does the windowClass property or NgbModalOptions actually do anything?

I am opening an NgbModal passing a TemplateRef to create the dialog body, and passing in a custom class via the windowClass property of the NgbModalOptions object that I pass to the open() method. I define the class in a referenced styleUrl in the component and am serving the modal via an injectable service in the component. The modal is loading fine, and I can see the class name when I inspect the DOM, but the class appears to have no bearing on the modal. I would like to use it to customize the size of the modal (css is defined to affect the child div where the size is set), but I have also played with properties that I can see in the Styles tab of the Chrome dev tools, but cannot see it affecting anything. When I inspect in Firefox dev tools, I can find the CSS as an inline style sheet and it has a reference to the ngContent identifier assigned by Angular, so I am assuming that is does not affect the entire document, nor those parts added by ng-bootstrap that constitute the modal wrapper. Has anyone been able to make this work successfully? I am at my wit's end. I would even be happy if I could get an ElementRef of the modal-header dive, but since I am using a template (which is not fully loaded in the DOM at init time) I have not been able to. One of my requirements is that we do all DOM manipulation via Angular to maintain platform independence in the project ... so no jQuery. Any thoughts? And thanks in advance!!
I use windowClass and size attributes of NgbModalOptions to customize the modal. Sample code follows:
this.modalService.open(<your_template_ref_var>, {size: 'lg', windowClass: 'modal-adaptive-s1'});
Whereas
.modal-adaptive-s1 .modal-lg {width: 400px !important; max-width: 400px;}

Vue.js 2.0 - creating reusable components

I am trying to create fully reusable component using Vue.js 2 and single file components, and right now my approach seems to be impossible to realize.
The goal is to create component for creating forms for a complex, nested JSON structure. This structure is supposed to be edited and then sent to the server. The component itself displays a header and submit button but the fields along with their placing is entirely the responsibility of the user of my component. (front-end engineer)
The MyForm component (implementation is not relevant here) is passed the JSON data and url to post them to.
The form is supposed to be reusable by many other users and the contents of the form itself is supposed to be not relevant. It may have a mix of html/inputs/custom components as children.
Let's imagine a simple scenario without data nesting with the following data:
var mymodel={ name : "My name", surname : "My surname" }
And a form i would like to create using my component:
<MyForm :model="mymodel" :url="http://localhost/post">
<div>
<MyTextInput v-model="model.name" label="Name"/>
<MyPanel>
<MyTextInput v-model="model.surname" label="Surname"/>
</MyPanel>
</div>
</MyForm>
Therefore:
MyForm gets passed a model to submit, stores it in data
MyTextInput is a custom component for displaying input with label
Second MyTextInput is the same component but created in another component contained called 'MyPanel' since this field needs to be placed differently.
As we can see there are many problems with passing variables and composition itself:
Composition:
If i put a <slot></slot> in the tempplate of MyForm for displaying the fields it would be compiled in parent scope, therefore all children (including MyTextField) would not have access to the "model"
If i try to use <MyForm inline-template> i cannot automatically display the form header and footer since all content is being replaced. Additionally when using single file components the compiler will look for all components inside the inline-template which means that i would have to import MyTextInput and MyPanel into MyForm which is not practical. I do not know in advance all components that will never end up in my form!
Passing variables:
If i use the variables directly from "model" (in first TextInput) i receive warning that i am modifying a variable from parent and it will be overwritten on next render (but in this case it will not be overwritten since i am INTENTIONALLY modifying the parent)
I cannot pass the model into second MyTextInput without passing it to MyPanel first. Actually i would have to pass it into EVERY custom component in between. And i do not know in advance how many custom components will there be. Which means that i would have to modify the code of every component that would ever be put into MyForm and require users to pass the data for each custom component they include.
If i would try to properly inform the parent about changes i would need to add v-on: event to every textinput and every custom component in between in order for the event to reach MyForm.
As i have said the component was supposed to be simple and easilly reusable. Requiring users of this component to modify code of every child they put into it and requiring them to add v-on: to every component inside does not seem practical.
Is my idea solvable using Vue.js 2.0 ? I have designed the same component before for AngularJS (1.5) and it was working fine and did not require to add modifications to each child of the form.
I've been using a ui framework based on vue 2.0 and you may get some ideas from its implementation. Based on its implementaion and my little experience with it, I think it's the person who uses your framework's responsibility to assemble the form-model. Also, for a form, we can always easily get all the data to be sent by using fields' value props without v-model's help.
The framework's doc on form element may also be helpful but it's currently only available in Chinese except for the code samples.
I suggest you to use Form Input Components using Custom Events to pass variables in your form.
Mutating a prop locally is now considered an anti-pattern, e.g.
declaring a prop a and then set this.a = someOtherValue in the
component. Due to the new rendering mechanism, whenever the parent
component re-renders, the child component's local changes will be
overwritten. In general, in 2.0 you should treat props as immutable.
Most use cases of mutating a prop can be replaced by either a data
property or a computed property.

Compile string with custom elements

I have an Aurelia application in which I'm trying to build a CMS component. This component will load data from the server and this data mainly contains slug, title and content fields.
I also have several global components defined in my application, and I want to be able to use those components in the server so when I pull that data my CMS component is able to transform/compile those custom elements.
An example would be a tab component. I have the tab component with this structure defined:
<tab-panel>
<tab title="First"></tab>
<tab title="Second"></tab>
</tab-panel>
The CMS component will contain a content property which I use to pass a string like this: '<tab-panel><tab title="First"></tab><tab title="Second"></tab></tab-panel>'
The component needs to compile that string and render it in its view. I've checked the enhance API, but it doesn't worked, at least for me. Any other suggestion to dynamically compile/render custom elements??
Thanks a lot in advance.
I've found the solution. I've used a compose element and InlineViewStrategy and it worked well, the components are shows and binding works as expected.
If your custom elements are registered globally using globalResources you can actually using the TemplatingEngine to dynamically insert content into the DOM and then compile it after-the-fact. This blog post goes into detail in how you can do it.
However, I would use this as a last resort. As is mostly always the case, there are much better ways to do something in Aurelia. Using the <compose> element is a great way to dynamically render content in your Aurelia applications and should always be the first port of call.

Attach/Render RactiveJS component outside of template

I've got an existing SPA that was developed using nested RactiveJS components. Which is great, and offers a ton of flexibility throughout the entire app. Currently I attempting to add in client side routing support using page. My navigation switches out high-level components using simple {{#visible}}{{/visible}} template markup on each component. This is a little troublesome in its current state as it always kicks off a re-render whenever the high-level component becomes visible again.
Is there a way to render a component, for example, called widget, without using the
<widget></widget>
method? I've already "registered" the component with the parent, but obviously when constructing it by means of
new App.components.widget
I am able to control how/when it's rendered/inserted/detached, but lose the recognition in the application's component hierarchy.
There is insert exactly for that. You don't even need to "register" it to the component you plan to put it to. You can use the different find* methods or nodes to easily retrieve a reference of your planned container element.
var instance = new YourDetachedWidget({ ... });
instance.insert('#your-container'); // This could be a node, selector or jQuery object