show ion-list over other elements - ionic4

I'm doing simple CRUD operation and on retrieving the object I am getting the list all saved objects and I want to search the list of objects by name. But I don't want to use ion-searchbar instead I want to use ion-input and show suggestions in ion-list under ion-input but overlapping other elements like any other search bar(like google search). I have data in JSON format.
I also try to use ionic4-autocomplete but facing error like
error image in ionic 4 app on auto complete
The solution to any of the problem will help.
thanks in advance.

Better List Filtering
There is a great project called ionic-selectable, which lets you have a nice searchable UI for lists of data.
Autocomplete Error
The formGroup error is because you haven't added in the Reactive Forms reference.
Find this line in the related module:
import { FormsModule } from '#angular/forms';
And change it to:
import { FormsModule, ReactiveFormsModule } from '#angular/forms';

Related

How to import HTMX variable?

I am using HTMX attributes on some dynamically generated DOM elements. HTMX is not working, as stated in the docs unless you call htmx.process().
When I tried to call this, I get - correctly - the error:
Uncaught ReferenceError: htmx is not defined
Any idea how I can import this htmx variable? No idea how the example in the docs can work.
Thx!
The non-module version of htmx.org defines a global, but you're using modules (via import). Half the point of modules is to do away with globals, and so the module version of it won't create a global, it'll return an export.
In a deleted comment you said the actual import is import "htmx.org" (not import htmx.org as in the comment that's still there). That being the case, you likely want one of these:
// Importing the default export
import htmx from "htmx.org";
// Or importing the module namespace object
import * as htmx from "htmx.org";
// Or importing a named export, but looking at the file I doubt you want this one
import { htmx } from "htmx.org";
Most likely, you want the first one.
You'd do that in the module where you're doing the htmx.process() call.
In your HTML file, after including Htmx, listen for the load event.
E.g. to enable logging:
<script>
document.body.addEventListener('htmx:load', function (evt) {
htmx.logAll();
});
</script>

Vue 3 - Load components based on backend setup

I would like to setup a dashboard in vue 3 where the admin can customize the template a bit. In fact he should been able to define the sorting of components. At the moment the dashboard loads its components the default way in one column:
template:
<ComponentA />
<ComponentB />
<ComponentC />
Script:
import ComponentA from '#assets/components/componentA';
import ComponentB from '#assets/components/componentB';
import ComponentC from '#assets/components/componentC';
The backend sorting for the components is not yet finally written so i'm still very flexible it could be an array of the component names but i will be able to set this based on the Vue requirements. Unfortunately i did not found anything regarding such a functionality to "load components based on a custom configuration" and not "hardcoded".
can please anyone point me into the right direction how to archive such a functionality? Maybe with some small explanation. I've tried already to build something via the methods but all i've got was compiling errors...
In fact an admin should be able to set another sorting like:
<ComponentC />
<ComponentA />
<ComponentB />
Additional note:
All other parameters for the frontend are saved in a global "moduleConfig" object which is defined in the index file - thats because it will be filled by PHP. There is no need to change the dashboard in realtime, on page load all settings are given, so no update hooks are required. My target is to save the wanted struct there also in form of an array or so (as i said not fix defined yet).
Maybe:
let moduleConfig = {
...
dashboardLayout: ['ComponentA','ComponentC','ComponentB'],
...
}

How to properly override a default spartacus Component

For the most part overriding an existing Spartacus works fine.
The Minimum amount of effort is
B2cStorefrontModule.withConfig({
cmsComponents: {
DefaultComponent: {
component: CustomComponent
}
},
Mostly I do this because I need to apply some changes to the components html.
So I copy and paste it to my generated customComponent.
But most of the times this html contains directives and pipes that require adding additional Modules to my app.modules.
Sometimes this works fine, but in many other cases the html just wont render.
Example: SearchBoxComponent
when trying to use the html I get a browser Error:
Error: Template parse errors:
The pipe 'cxHighlight' could not be found ("
<a
*ngFor="let suggestion of result.suggestions"
[innerHTML]="[ERROR ->]suggestion | cxHighlight: searchInput.value"
[routerLink]="
{
"): ng:///AppModule/EmvSearchBoxComponent.html#49:21
In other cases I was able to fix this by including the corresponding module that references this pipe "cxHighlight". In this case "SearchBoxModule". But still no good.
How do make this pipe available in my project?
Or maybe there is an even better way around all this importing pain?
You are correct in the way you are overriding components in Spartacus. Like you noticed certain components contain pipes so you will have to manually import those in your components module. This is just the Angular way.
Most of our pipes are reused in multiple components so we try to make them have their own modules to make imports easier.
You are correct about cxHighlight, there is a bug. The pipe is declared in the SearchBoxModule but not exported so it's pretty much impossible to import. I will open an issue to have it fixed.

How to render a custom component into a map's marker popup?

I am using a Vue plugin component Timeago, and i want to show a timeago time in the content of a map plugin. A super-simplified example to illustrate the usage would be something like:
let popup = L.responsivePopup().setContent(`
<h1>Hello world</h1>
<p>A thing happened <Timeago datetime="${datetime}"></Timeago></p>
`);
L.marker([lat, lon]).bindPopup(popup).addTo(this.map);
According to this answer, and Vue's documentation, i should be able to compile this using Vue.compile(), but i am not understanding the concept.
First, there is no explanation on what a "full build" is. How can i tell if what i have is a "full build"? Searching for "vuejs full build" doesn't return anything that is being referred to as literally that phrase, even though they use it in the documentation there. All i know is that when i try to call Vue.compile() with having imported import Vue from 'vue', it complains saying:
TypeError: vue__WEBPACK_IMPORTED_MODULE_6__.default.compile is not a function
So i don't know where to go from there.
And then second thing is (assuming the first thing gets sorted), will i have to make my HTML hold an empty div with a specific id, wait for it to render, and then call the Vue.compile() on it, since the sample code there runs with .mount() on an element id? Because that seems a little "incorrect", having seemingly an extra step. Or is that the only way to make this scenario work?
If there is an alternative simpler wait of making this work, like getting the Timeago component to just return the rendered string only, such as 2 hours ago that i can incorporate into my string literal, that would work for me as well. Either way is fine.
Vue has differents build of it's package, full means that package can compile templates and and run it. All build types can be found here https://v2.vuejs.org/v2/guide/installation.html#Explanation-of-Different-Builds
Vue.compile allows you to use render functions, which allow you to manipulate DOM and create elements in a programmatic way. Here you can find Vue documentation about it https://v2.vuejs.org/v2/guide/render-function.html
About the issue you are facing, you can create a vue component and put that popup inside it, this component when render will render the timeago component.
<template>
<h1>Hello world</h1>
<p>A thing happened <Timeago datetime="${datetime}"></Timeago></p>
</template>
import Timego from './Timeago.vue'
export default {
components: {
Timeago
},
props: {
datetime: String
}
}

How to update vue2-frappe chart?

I've been breaking my head over this for the last few hours and no matter where I look I can't seem to find the answer.
I'm using vue2-frappe as my chart library. I'm using a simple bar chart to display certain values by day. Everything was fine until my higher-ups decided they wanted to show a whole year's worth of values on this chart, meaning I have to add some pagination to it.
The problem is, now I can't figure out how to make the chart rerender. I've tried replacing the entire object I've bound the chart to, as well as manipulating specific values, but nothing seems to make the component rerender.
In the documentation for frappe.js, you can modify data via specific methods, but this being Vue I can't just call chart.update() like in normal .js. And if I inspect the component via vue dev tools, I can see it contains the modified data, it just doesn't redraw itself.
Anyone have an idea what to do?
I would try to force update the view component.
VueJs reactivity can sometimes be confusing where you think it should react to changes but it doesn't.
You can force a view update like so:
// Globally
import Vue from 'vue';
Vue.forceUpdate();
// Using the component instance
export default {
methods: {
methodThatForcesUpdate() {
// ...
this.$forceUpdate(); // Notice we have to use a $ here
// ...
}
}
}
You can read about correct ways of re-rendering here: https://michaelnthiessen.com/force-re-render
There are caveats to this approach as outlined in vueJs's docs: https://v2.vuejs.org/v2/guide/list.html#Caveats
Note #
A force re-render wont update computed values, but your computed property shouldn't contain any external non-reactive variable anyway.
Note 2
The above article written by Michael Thiessen also states the best way in his opinion is key-changing which I think we all should be aware of.
I hope this puts you on the right track. It sounds like (with limited information) you could be replacing the data but using the same key.