How to use javascript libraries that require binding to DOM nodes - ag-grid

I have been trying to use Ag-Grid with Svelte. I understand that the main problem with using this grid library is that it needs to bind to a dom element that may not exist at the time of the code executing. For example:
// lookup the container we want the Grid to use
var eGridDiv = document.querySelector('#myGrid');
In this case, the #myGrid element does not exist yet.
I have tried creating an element and then placing it on the HTML part of the Svelte component, like this.
let eGridDiv = document.createElement("DIV");
let gridOptions = { columnDefs: columnDefs, rowData: $orders };
new Grid(eGridDiv, gridOptions);
And then down on the HTML section
<eGridDiv />
However, the new element does not seem to be initialized by Ag-Grid.
So what is the recommended way to use these types of libraries in Svelte?

If you want to use a DOM node in the script part of your component you can use the bind:this={domNode} element binding to get a reference to it, and then use it after the component has been rendered in onMount.
<script>
import { onMount } from 'svelte';
let domNode;
// ...
onMount(() => {
const gridOptions = { columnDefs: columnDefs, rowData: $orders };
new Grid(domNode, gridOptions);
});
</script>
<div bind:this={domNode} />

Related

Is it possible in vue3 to access the root DOM element in a child component slot? I am trying to use a 3rd party library (sortablejs) in vue3

In vue2 I could use this.$el
export default {
render() {
return this.$slots.default[0]
},
mounted() {
Sortable.create(this.$el, {});
})
}
If, in vue3 I try to use this.$slots.default()[0] I can't see how to target the element.
If I use a template ref, I can get the div, but not the contained slot.
The closest question / answer I have found is here Vue 3 Composition API - How to get the component element ($el) on which component is mounted
but this also seems to give the div, but not the slot $el.
This was extremely powerful in vue2 because sortable could be passed a ul, or a div, or another constructed sortable vue component in a slot, and work without the element having to be defined in the child component and I can't work out how to replicate this in vue3.
I originally came across this in a screen cast by Adam Wathan: "Building a Sortable Component with Vue.js", but this was vue2.
I've come up with the following (perhaps there are better out there)
Use template ref:
<template>
<div ref="root">
<slot></slot>
</div>
</template>
Then in the script:
import { ref, onMounted } from 'vue'
export default {
setup() {
const root = ref(null)
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
// console.log(root.value.children[0]) // this is your $el
let el = root.value.children[0]
Sortable.create(el, {})
})
return {
root
}
}
}

Can't get ag-grid to display

I have a basic ag-grid with some simple dummy data, but it only displays when I don't import the .css files provided with the library, and even then it displays incorrectly.
Excerpted from my package.json:
"ag-grid": "10.0.1",
"ag-grid-react": "10.0.0",
"react": "15.4.2"
From my React component:
constructor:
this.state = { columnDefs: [{headerName: 'Product', field: 'product'},{headerName: 'Country', field: 'country'}], rowData: [{product: 'IOL', country: 'US'}, {product: 'Suture', country: 'IN'}]}
from render():
return (
<div id='grid'>
{/*<div id='grid' className='ag-fresh'>*/}
<div>
Here's the grid...
</div>
<AgGridReact
// listen for events with React callbacks
onGridReady={this.onGridReady.bind(this)}
// onRowSelected={this.onRowSelected.bind(this)}
// onCellClicked={this.onCellClicked.bind(this)}
// binding to properties within React State or Props
showToolPanel={this.state.showToolPanel}
quickFilterText={this.state.quickFilterText}
icons={this.state.icons}
// column definitions and row data are immutable, the grid
// will update when these lists change
columnDefs={this.state.columnDefs}
rowData={this.state.rowData}
// or provide props the old way with no binding
rowSelection="multiple"
enableSorting="true"
enableFilter="true"
rowHeight="22"
/>
</div>)
If I run this code without importing any .css I get a jumbled grid like:
Now if I import the css per the getting started guide:
import 'ag-grid-root/dist/styles/ag-grid.css' // see webpack config for alias of 'ag-grid-root'
import 'ag-grid-root/dist/styles/theme-fresh.css'
... then no part of the grid displays (only my div before the grid). With the css imported, it doesn't matter if I have assigned a theme to the grid or not, nothing shows.
I had a similar problem with the rows of data not showing, just the pagination. Setting a fixed div height worked to make the rows display, but adding domLayout: 'autoHeight' to the gridOptions means its always the right height to display correctly.

Leaflet-draw control's toolbar not displaying

I'm trying to use Leaflet-draw in VueJS, after calling it
import LeafletDraw from 'leaflet-draw'
But when I'm trying to use it
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems
}
});
map.addControl(drawControl);
I only have a partial control's toolbar
Am I missing a CSS file to include ?
If someone is still looking for a solution so inside the vue component for example Map.vue you need to add this:
<script>
import "leaflet-draw/dist/leaflet.draw.css";
.
.
.
</script>
The issue was related to this one https://github.com/Leaflet/Leaflet.draw/issues/617
Importing the CSS file directly in my component and overriding the CSS property did the trick (with a valid path to the sprite; in Vue case, the static folder)
.leaflet-draw-toolbar a {
background-image: url('/static/spritesheet.png');
}

Working with openlayers and typescript classes

/// <reference path="openlayers.d.ts" />
class MapComponent {
element: HTMLElement;
map: OpenLayers.Map;
constructor(element: HTMLElement) {
// Setup our map object
this.element = element;
this.map = new OpenLayers.Map(this.element);
}
init() {
// Setup our two layer objects
var osm_layer_map = new OpenLayers.Layer.OSM("OSM");
// Add layers to the map
this.map.addLayers([osm_layer_map]);
// Add a layer switcher control
this.map.addControl(new OpenLayers.Control.LayerSwitcher({}));
// Zoom the map to the max extent
if (!this.map.getCenter()) {
this.map.zoomToMaxExtent();
}
}
}
window.onload = () => {
var el = document.getElementById('map');
var mc = new MapComponent(el);
mc.init();
}
I have the above piece of code to work with a simple HTML file with only 1 of ID, 'map' with style: height and width # 500px.
I have tried several other ways to get the map to display but so far all i got was a white page (blank).
Can anybody point me in the right direction?
Solutions tried so far:
using jquery with ready function
replace window.onload with a call direct from the html, <script><script/>
place document.getElementById() in the new OpenLayers.Map(here); when first creating this.map
placing the window.onload call above and below (currently)
using export class or public init() or both
As of now, I just want it to work.
Seems that creating the map with the element provided and later defining the options doesn't work.
Instead either initialize the map with options
var options = {
projection: "EPSG:3857",
maxExtent: new OpenLayers.Bounds(-200000, -200000, 200000, 200000),
center: new OpenLayers.LonLat(-12356463.476333, 5621521.4854095)
};
this.map = new OpenLayers.Map(this.element, options);
Or call this.map.render(this.element) at the end of your init method.
Also make sure your div is actually visible and has some size specified, otherwise it might be not visible...

AngularJs Directive: Using TemplateURL. Replace element. Add form input. Getting form.input.$error object

Not sure if this is possible but I'm trying, and keep coming up short.
http://plnkr.co/edit/Gcvm0X?p=info
I want a 'E' (element) directive that is replaced with a more complex nested HTML node using the 'templateUrl' feature of directives.
HTML defining the directive (form tag included for complete mental image):
<form id="frm" name="frm">
<ds-frm-input-container
class="col-md-1"
frm-Name="frm"
frm-obj="frm"
input-name="txtFName"
ds-model="user.firstName"></ds-frm-input-container>
</form>
TemplateUrl contents which 'replaces' the above directive 'ds-frm-input-container' HTML element:
<div>
<input
required
ng-minlength=0
ng-maxlength=50
class="form-control"
ng-model="dsModel"
placeholder="{{dsPlaceHolder}}" />
<span ng-if="showErrs" class="label label-danger">FFFFF: {{dsModel}}</span>
</div>
Controller and Directive:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = "Nacho";
$scope.user = {};
$scope.user.firstName = "";
})
.directive('dsFrmInputContainer', function(){
var ddo = {
priority: 0,
restrict: 'AE',
scope:
{
frmName: '#',
inputName: '#',
dsPlaceHolder: '#',
dsModel: '=',
frmObj: '='
},
templateUrl: 'template1.html',
replace: true,
controller: function($scope)
{
$scope.showErrs = true;
},
compile: function compile(ele, attr) {
return {
pre: function preLink(scope, ele, attr, controller)
{
},
post: function postLink(scope, ele, attr, controller)
{
var txt = ele.find('input');
txt.attr('id', scope.inputName);
txt.attr('name', scope.inputName);
//BLUR
txt.bind('blur', function () {
console.log("BLUR BLUR BLUR");
angular.forEach(scope.frmObj.$error, function(value, key){
var type = scope.frmObj.$error[key];
for(var x=0; x < type.length; x++){
console.log(type[x]);
}
});
event.stopPropagation();
event.preventDefault();
});
}
};
},
};
return ddo;
});
The directive replaces just fine and the input element is named just fine. The form object however doesn't include the input element name in the error information. This makes it impossible for me to single out the input element during a 'blur' event that is setup in the directive.
I am doing this trying to reduce the show/hide logic 'noise' in the html for error messages (spans) and it should be reusable.
UPDATE (2014.01.28):
2014.01.28:
Added promises. There is a service that allows validation on button clicks. NOT USING built in angular validation anymore found some compatibility issues with another library (or viceversa).
ORIGINAL:
Here is my form validation directive vision completed (plnkr link below). Completed in concert with the help of the stack overflow community. It may not be perfect but neither are butterfingers but they taste good.
http://plnkr.co/edit/bek8WR?p=info
So here is a link that has the name variables set as expected on the given input form error object. http://plnkr.co/edit/MruulPncY8Nja1BUfohp?p=preview
The only difference is that the inputName is read from the attrs object and is not part of the scope. This is then read before the link function is returned, in the compile phase, to set the template DOM correctly.
I have just spent quite a while trying to sort this problem out, and while this is not exactly what you were looking for, his is my attempt. It uses bootstrap for all the styling, and allows for required and blur validation, but its definitely not finished yet. Any thoughts or advice much appreciated.
https://github.com/mylescc/angular-super-input