How to call gridready event of AG-Grid on a click Handler function - angular2-template

I am working on a project in my organization where I have to implement ag-grid .I know ag-grid has a gridready event function which fires initially and sets the params with all grid api properties . My rowdata is constantly changing which is coming from some other component ,I have added a handler (function) where I want to call gridready event again which sets my rowdata with the latest values . The problem is gridapi properties will be initialized only at 1st time ,I want to access those (gridapi) properties in my handler as well which is becoming undefined now ,how to access gridapi properties even after grid initialization and scope is lost. I don't have the exact code ,I have added some code snapshots which will describe my situation exactly.
grid.component.ts
#Input() gridData
ngOnit() {
}
handler() {
want to call grid ready but params will be undefined ,how to set this gridapi properties.
gridready()
}
gridready(params) {
this.gridapi =params.api;
this.columnapi =params.clumnapi
this.gridapi.setRowData(this.gridData.rowData)
}

According to ag-Grid's documentation, the Grid API (both api and columnApi) will only be available after the gridReady event has been fired.
Here's an alternative way of achieving the same thing if I understood your problem correctly.
You can try adding a local variable, isGridAPIReady, in your own grid.component.ts to track that state.
Set isGridAPIReady to true when ag-grid GridReadyEvent fires.
And eventually set the new rowData using the grid api:
//grid.component.ts
#Input()
rowData: any[];
ngOnChanges(changes: SimpleChanges): void {
if (this.isGridAPIReady && changes['rowData']) {
this.gridOptions.api.setRowData(this.rowData);
}
}
Hope it helps!

Related

Trying to get vue.js to render something conditionally based on a method in created()

I have a call in my created method which has an await.
I want to know that the results of that call are loaded so that i can conditionally show/hide things in the DOM.
Right now it looks like the DOM is being rendered before that method has completed. But I though that methods in created were called before the DOM rendered?
You're correct in assuming that the created hook runs before the component mounts. However, the lifecycle hooks are not waiting for async calls to complete. If you want to wait for that call to be completed and data to load, you can do so by using a Boolean that you set to true when your data has loaded.
Your template:
<div v-if='dataLoaded'>Now you can see me.</div>
in your vue instace
export default {
data () {
return {
dataLoaded: false
}
},
created () {
loadMyData().then(data => {
// do awesome things with data
this.dataLoaded = true
})
}
}
This way you can keep your content hidden until that call has resolved. Take care with the context when you handle the ajax response. You will want to keep this as a reference to the original vue instance, so that you can set your data correctly. Arrow functions work well for that.

Programatically assign handler for native event in Vue JS?

I am trying to leverage a Vue mixin to add behavior when a native event happens. Using a mixin will allow me to share that across several components. Specifically, when a field component (or button, or checkbox, etc.) has focus, and the Escape key is pressed, the field loses focus.
A similar Stack Overflow question seemed to indicate I could listen for native events (see code comment about multiple events).
However, the Vue Documentation for programmatically adding an event listener using $on says that it will
Listen for a custom event on the current vm...
(Emphasis added)
Unsure if the custom event remark is absolute or based on the context, I have been experimenting. I have been trying to listen for the native keyup event (using the Vue alias keyup.esc) but have had no success. So I am wondering if it is indeed limited to custom events, and if so, why?
You can see my experiment in a code sandbox. The custom event works, the native does not.
The mixin looks like so:
// escape.mixin.js
export default {
created() {
// Custom event
this.$on("custom-event", function() {
console.log("Custom event handled by mixin");
});
// Native event
this.$on(["keyup.esc", "click"], function() {
alert("Native event handled!");
});
}
};
The main point of all this is to be able to add the behavior to a set of components by adding to how the event is handled, without overriding behavior that might also exist on the component. The secondary goal is to provide the behavior by simply adding the mixin, and not having to do component level wiring of events.
So a component script would look something like this:
// VText component
import escapeMixin from "./escape.mixin";
export default {
name: "VText",
mixins: [escapeMixin],
methods: {
onFocus() {
console.log("Has Focus");
this.$emit("custom-event");
}
}
};
Also, I was trying to avoid attaching the listener to the <input> element directly with vanilla JS because the Vue documentation suggested that letting Vue handle this was a good idea:
[When using v-on...] When a ViewModel is destroyed, all event listeners are automatically removed. You don’t need to worry about cleaning it up yourself.
Solution
skirtle's solution in the comment below did the trick. You can see it working in a code sandbox.
Or here's the relevant mixin:
export default {
mounted() {
this.$el.addEventListener("keyup", escapeBlur);
},
beforeDestroy() {
this.$el.removeEventListener("keyup", escapeBlur);
}
};
function escapeBlur(e) {
if (e.keyCode === 27) {
e.target.blur();
console.log("Lost focus");
}
}

Making small components on runtime

I am having a problem working with JQuery DataTable. I had to use that plugin since I had no other choice allowed due to my project requirements.
So the problem is that, I am adding rows to DataTable and in the row there's a column with button HTML tag. Now I want to bind an on click handler to the button.
dt.Rows.Add({
column_1_data,
column_2_data,
"<button #click='itsVueTime'>MyButton</button>"
});
Here dt is the DataTable's instance. Now the problem is #click won't work. I understand that its not being rendered by Vue thats why its not working.
Is there a way to bind click event in this condition?
Without knowing more context, I would recommend this way of doing it
In your component with the method you want to use, you can expose the component like this. (I use mounted, but you can use other lifecycle methods too like created)
mounted() {
window.app = this;
}
then you can use
<button onclick="app.holler()">Say Hello</button>
you can also expose just the function you want to use like so
mounted() {
window.itsVueTime = this.itsVueTime;
}

Vuetify and require.js: How do I show a dynamic component?

I am creating a tab component that loads its v-tab-item components dynamically, given an array of configuration objects that consist of tabName, id, and tabContent which is a resource location for the component. I have it successfully loading the components. However, they don't actually initialize (or run their created() methods) until I switch tabs. I just get empty tabs with the correct labels. Using the DOM inspector initially shows just <componentId></componentId>, and then when I switch tabs, those tags are replaced with all of the component's content.
How do I get the dynamic components to initialize as soon as they are loaded?
EDIT: I created a CodePen here:
https://codepen.io/sgarfio/project/editor/DKgQON
But as this is my first CodePen, I haven't yet figured out how to reference other files in the project (i.e. what to set tabContent to so that require.js can load them up). I'm seeing "Access is denied" in the console, which makes it sound like it found the files but isn't allowed to access them, which is weird because all the files belong to the same project. So my CodePen doesn't even work as well as my actual project. But maybe it will help someone understand what I'm trying to do.
Also, after poking around a bit more, I found this:
http://michaelnthiessen.com/force-re-render/
that says I should change the key on the component and that will force the component to re-render. I also found this:
https://v2.vuejs.org/v2/guide/components-dynamic-async.html
Which has a pretty good example of what I'm trying to do, but it doesn't force the async component to initialize in the first place. That's what I need the async components to do - they don't initialize until I switch tabs. In fact they don't even show up in the network calls. Vue is simply generating a placeholder for them.
I got it working! What I ended up doing was to emit an event from the code that loads the async components to indicate that that component was loaded. The listener for that event keeps a count of how many components have been loaded (it already knows how many there should be), and as soon as it receives the right number of these events, it changes the value of this.active (v-model value for the v-tabs component, which indicates which tab is currently active) to "0". I tried this because as I noted before, the async components were loading/rendering whenever I switched tabs. I also have prev/next buttons to set this.active, and today I noticed that if I used the "next" button instead of clicking on a tab, it would load the async components but not advance the tab. I had already figured out how to emit an event from the loading code, so all I had to do at that point was capture the number of loaded components and then manipulate this.active.
I might try to update my CodePen to reflect this, and if I do I'll come back and comment accordingly. For now, here's a sample of what I ended up with. I'm still adding things to make it more robust (e.g. in case the configuration object contains a non-existent component URL), but this is the basic gist of it.
created: function() {
this.$on("componentLoaded", () => {
this.numTabsInitialized++;
if(this.numTabsInitialized == this.numTabs) {
// All tabs loaded; update active to force them to load
this.active = "0";
}
})
},
methods: {
loadComponent: function(config) {
var id = config.id;
var compPath = config.tabContent;
var self = this;
require([compPath], function(comp) {
Vue.component(id, comp);
self.$emit("componentLoaded");
});
}
}

How to bind custom event handler from vue-touch-events to a custom component in Vue.js

I'm currently implementing a classical Minesweeper game in Vue.js which is working fine so far https://github.com/franktopel/defuse, Demo http://connexo.de/defuse/.
Now I would like to add touch support because as of now, to mark a field as "contains a mine" it is required that you right-click the field. Right-clicking is obviously not available on touch devices, so I would like to add longtap support. I'm using native events click and click.right from the parent component for each field, so the field does not handle the events, but the parent component that instantiates these fields does.
I've found this https://github.com/jerrybendy/vue-touch-events and added it to my project, yet it seems I cannot use this on the component tag (see https://github.com/franktopel/defuse/blob/master/src/components/Defuse.vue):
<m-field
v-for="field in row"
:field="field"
:key="`${field.x},${field.y}`"
#click.native="open(field)"
#click.right.native.prevent="toggleBombMarker(field)"
v-touch:longtap="toggleBombMarker(field)"
></m-field>
because that marks all fields without any user interaction and the console keeps producing
You may have an infinite update loop in a component render function.
This is how my field objects (which I'm passing to the field component) are created:
let Field = function (x, y) {
this.x = x
this.y = y
this.isOpen = false
this.hasBomb = false
this.isMarked = false
this.numNeighbourBombs = null
}
module.exports = Field
I have also tried emitting a custom event from inside my field component, yet I don't know how I can pass the triggering field to the event handler from there.
Can anyone push me in the right direction?
According to the vue-touch-events docs, the v-touch directive doesn't work in the same way as v-on; v-touch must be given a function to execute, whereas the toggleBombMarker(field) expression probably returns undefined.
If you want to pass extra parameters to the v-touch handler, your handler must return a function like this:
methods: {
toggleBombMarker(field) {
return () => {
// your handler code here
}
}
}