Binding selectize with aurelia - selectize.js

I am trying to use selectize with aurelia.io
I have created template shop.html
<template>
<input ref="content" type="text" value.two-way="shops" >
</template
and in my class shop with adnotation #customElement('shop') I
am trying to bind selectize.js to #bindable shops
attached() {
var s = $(this.content).selectize({
delimiter: ',',
persist: false,
create: function(input) {
return {
value: input,
text: input
}
}
});}
I am using this custom element with template books, like this:
<shop shops.two-way="selected.data.bookshops" ></shop>
Two way data binding is not working as I expected.
Selectize value is only updated for the first time.

I have found the need to capture selectize's change event in my custom element and propagate it to the original select input, in order for Aurelia's data binding to work. Add a change handler on the selectize to propagate the event.
// init selectize
this.sel = el.selectize(opts)[0]; // first element
// on change after setting initial value
this.sel.selectize.on('change', () => {
// no event param passed in
console.log(`Selectize change event`);
// dispatch to raw select within the custom element for data binding trigger
// bubble it up to custom event in case change event is handled
let notice = new Event('change', {bubbles: true});
$(el)[0].dispatchEvent(notice);
});
By bubbling up the change event, this will also allow you to add an change.delegate handler on your custom element when it is used in a view.
<selectize ... change.delegate='changeHandler()'>

You have to install selectize which depends on sifter, microplugin and jquery
jspm jquery
jspm install selectize
jspm install sifter
jspm install microplugin
Then you can import and use it
import $ from 'jquery';
import selectize from 'selectize';

Related

How to setState of redux wrapped component?

I'm trying to test a component that is wrapped in Redux:
beforeEach(async () => {
component = await mount(
<Provider store={buildStore()}>
<CheckoutOverlay cartItems={basicCart} />
</Provider>
)
await component.update();
})
Things I've tried:
component.find(CheckoutOverlay).instance().state.coupon={} (Cannot read 'state' of null)
component.find(CheckoutOverlay).state.coupon={mode:0, value:.25}; (state does not update)
component.find(CheckoutOverlay).setState({coupon: {mode: 0, value: .25}}); (setState() can
only be called on class components)
component.find(CheckoutOverlay).instance().setState({coupon: {mode: 0, value: .25}}); (cannot read property 'setState' of null)
I've also tried some suggestions that use SHALLOW() and .dive(). But I always get the error 'dive()' is not a function. I am using Enzyme 3.11.0
How can I update the state of a component wrapped in the Redux Provider?
Additional Info:
Inside my component, CheckoutOverlay, I have another component that calls a function in CheckoutOverlay. This function stores the data sent in the State.
I am trying to simulate what happens when the data is sent to CheckoutOverlay.
The sub component has tests, and, I suppose, I can do something like simulate the click on that component. But that seems like it is more involved than it should be.
Since you have not mentioned what you are trying to test, I am giving you some general suggestions.
You should not test the implementation details, rather test the functionality.
If your state is dependant on the redux store state, you can pass the required data as initialState to your provider.
You cannot use instance on a functional component

How can useEffect WITH [] argument run multiple times

In what cases can such a structure
useEffect(() => {
...
}, []);
run multiple times?
I thought it shouldn't by definition, but on this video it does:
https://www.youtube.com/watch?v=7RMwZ0_tANg
[] means, that it will render only on initial render, so probably there is multiple rendering of a component
The way you used useEffect it is working as equality to componentDidMount for class component.
useEffect can be used as componentDidMount , componentDidUpdate and componentWillUnmount.
useEffect(() => {
console.log('mounted'); //This way you can get componentDidMount
return () => console.log('unmounting...'); //This way you can get componentDidUnmount
}, []) // <-- The effect depends on variable you put into array(if you would want to check and do something every time variable did update you would put variable name inside - componentDidUpdate)
I found out, how that was possible.
const ComponentWithLoader = WithLoader(Component);
return <ComponentWithLoader { ...{
isLoading, data, remove, update, setData, ...props,
}}/>;
I used a higher-order component inside the body of a functional component. And since WithLoader call created a completely new component every time, the whole component structure inside it was recreated on every rerender of the outer functional component.

How to register custom cell renderer in pe:sheet? [duplicate]

I am trying to implement a custom cell renderer to the pe:sheet component.
As this component is based on Handsontable, I tried the approach as described here:
https://handsontable.com/docs/6.2.2/demo-custom-renderers.html
I also changed the code for registering from Handsontable.renderers.registerRenderer('myRenderer', myCustomRenderer);
to
this.cfg.renderers.registerRenderer('myRenderer', myCustomRenderer);
in an attempt to access the instance of handsontable inside pe:sheet.
I am calling my sheetExtender via the extender attribute of pe:sheet.
function sheetExtender() {
// this.cfg.renderers.registerRenderer('myRenderer', myCustomRenderer);
// Handsontable.renderers.registerRenderer('myRenderer', myCustomRenderer);
console.log(this);
}
var myCustomRenderer = function (instance, td, row, col, prop, value, cellProperties) {
$(td).empty().append('TEST');
};
Adding 'myRenderer' to the colType attribute of a pe:sheetcolumn, I would expect the column values to be overwritten by 'TEST'.
When I use 'this.cfg...' I get an Uncaught TypeError: Cannot read property 'registerRenderer' of undefined.
When I use 'Handsontable...' I don't get the error, but no results either, as, I guess, this approach propably didn't add the renderer to the actual instance of handsontable.
Is there a way to add custom cell renderers in pe:sheet, or at least make a cell render HTML?
I am the author of pe:sheet. If you want to customize the renderer you can do the following...
This is where it happens in the component: https://github.com/primefaces-extensions/core/blob/master/src/main/resources/META-INF/resources/primefaces-extensions/sheet/1-sheet.js#L59-L116
You can just override the default TextCellRenderer with your own.
function sheetExtender() {
this.cfg.textCellRenderer = function (instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.HtmlRenderer.apply(this, arguments);
// call your custom renderer method here
myCustomerRenderer(instance, td, row, col, prop, value, cellProperties);
}
}

How can I break this code up into two RequireJs modules

I've created the code below to dynamically load 2 buttons into an element with an ID of masthead. Then a function called showMenus runs when each button is clicked, running some jQuery animations. Everything is wrapped inside of a RequireJS module.
The code works fine as is but I'm thinking it may be better to break it up into two separate RequireJS modules/files: one that loads the buttons on the page and another one that runs the showMenus function. I did refer to the RequireJS API docs but couldn't find an answer.
Any help is appreciated...thanks in advance!
require(['jquery'], function ($) {
var header = document.getElementById("masthead"),
$navMenu = $("#site-navigation-list"),
$searchBox = $("#searchform"),
menuButton = document.createElement("div"),
searchButton = document.createElement("div"),
showMenus;
$(menuButton).attr("id", "menu");
$(searchButton).attr("id", "search");
header.appendChild(searchButton);
header.appendChild(menuButton);
// break the code below into its on RequireJS module?
showMenus = function(btn,el) {
$(btn).click(function() {
if (el.is(":visible") ) {
el.slideUp({
complete:function(){
$(this).css("display","");
}
});
} else {
el.slideDown();
}
});
};
showMenus(menuButton, $navMenu);
showMenus(searchButton, $searchBox);
});
What follows is only my opinion, but you might find it useful.
It might help to think in terms of things that your app is made of, and then maybe they are candidates for modules. So in your example, a 'masthead' seems to be a thing that you are interested in.
So using RequireJS, we can create a new module representing a generic masthead:
// Masthead module
define(['jquery'], function ($) {
function showMenus (btn, el) {
function toggle (el) {
if (el.is(":visible")) {
el.slideUp({
complete:function(){
$(this).css("display","");
}
});
} else {
el.slideDown();
}
}
$(btn).click(function() {
toggle(el);
});
}
// A Masthead is an object that encapsulates a masthead DOM element.
// This is a constructor function.
function Masthead (mastheadElement) {
// 'this' is the masthead object that is created with the 'new'
// keyword in your application code.
// We save a reference to the jQuerified version of mastheadElement.
// So mastheadElement can be a DOM object or a CSS selector.
this.$mastheadElement = $(mastheadElement);
}
// Add a method to Masthead that creates a normal button
Masthead.prototype.addButton = function (id) {
var $btn = $("<div/>").attr("id", id);
this.$mastheadElement.append($btn);
return $btn;
};
// Add a method to Masthead that creates a 'toggling' button
Masthead.prototype.addTogglingButton = function (id, elementToToggle) {
// ensure we have a jQuerified version of element
elementToToggle = $(elementToToggle);
// Reuse the existing 'addButton' method of Masthead.
var $btn = this.addButton(id);
showMenus($btn, elementToToggle);
return $btn;
};
// return the Masthead constructor function as the module's return value.
return Masthead;
});
And then use this module in our actual application code:
// Application code using Masthead module
require(["Masthead"], function (Masthead) {
// We create a new Masthead around an existing DOM element
var masthead = new Masthead("#masthead");
// We add our buttons.
masthead.addTogglingButton("menu", "#site-navigation-list");
masthead.addTogglingButton("search", "#searchform");
});
The advantage of this approach is that no DOM ids are hard-coded into the module. So we can reuse the Masthead module in other applications that require this functionality, but which may be using different DOM ids.
It might be convenient to think of this as separating the what things are from the how we use them.
This is a simple example, but frameworks/libraries like Backbone and Dojo (and many, many more) take this further.

Extending the YUI Panel

I have a requirement to extend the YUI Panel with some custom functionality that will be in a new file and shared across multiple views.
I am at a bit of a loss as to how best to go about this, can anyone give me any pointers please?
Let's say you want to extend a Panel to create one that has a list in its body. I usually use Y.Base.create for this. It's a more declarative way of extending YUI classes than using a constructor and Y.extend. But I'll stay closer to your example in the YUI forums.
There are a couple of tricks dealing with WidgetStdMod (one of the components of Y.Panel), but mostly it's just about using Y.extend and following the YUI inheritance patterns. I'll try to answer with an example:
function MyPanel() {
MyPanel.superclass.constructor.apply(this, arguments);
}
// hack: call it the same so you get the same css class names
// this is good for demos and tests. probably not for real life
MyPanel.NAME = 'panel';
MyPanel.ATTRS = {
listItems: {
// YUI now clones this array, so all's right with the world
value: []
},
bodyContent: {
// we want this so that WidgetStdMod creates the body node
// and we can insert our list inside it
value: ''
}
};
Y.extend(MyPanel, Y.Panel, {
// always a nice idea to keep templates in the prototype
LIST_TEMPLATE: '<ul class="yui3-panel-list"></ul>',
initializer: function (config) {
// you'll probably want to use progressive enhancement here
this._listContainer = Y.Node.create(this.LIST_TEMPLATE);
// initializer is also the place where you'll want to instantiate other
// objects that will live inside the panel
},
renderUI: function () {
// you're inheriting from Panel, so you'll want to keep its rendering logic
// renderUI/bindUI/syncUI don't call the superclass automatically like
// initializer and destructor
MyPanel.superclass.renderUI.call(this);
// Normally we would append stuff to the body in the renderUI method
// Unfortunately, as of 3.5.0 YUI still removes all content from the body
// during renderUI, so we either hack it or do everything in syncUI
// Hacking WidgetStdModNode is doable but I don't have the code around
// and I haven't memorized it
//var body = this.getStdModNode('body');
},
syncUI: function () {
// same here
MyPanel.superclass.syncUI.call(this);
// insert stuff in the body node
var listContainer = this._listContainer.appendTo(this.getStdModNode('body'));
Y.Array.each(this.get('listItems'), function (item) {
listContainer.append('<li>' + item + '</li>');
});
}
});

Resources