Re-render cornford/googlmapper on Livewire - laravel-livewire

I'm starting the map with the coordinates (0, 0) and i have a list of available coordinates, and when i click on one of them i fire a function that updates map coordinates to re-center it.
I'll past the code from the controller:
class myClass extends Component
{
public $latitude = '0.0';
public $longitude = '0.0';
public function centerMap($id)
{
$dg = DeliveryGuyDetail::find($id);
$this->latitude = $dg->delivery_lat;
$this->longitude = $dg->delivery_long;
}
public function render()
{
Mapper::map($this->latitude, $this->longitude, ['zoom' => 18, 'async' => true, 'clusters' => ['size' => 20, 'center' => true], 'draggable' => true ]);
return view('livewire.manager.delivery-map');
}
}
The goal is to re-center the map after the user click on the available coordinates on frontend and fire the function "centerMap" to recenter the map. But when that happens the map disappear.
Any advice on that?
Thanks in advance.

Try calling the render methiod in the component:
public function centerMap($id)
{
$dg = DeliveryGuyDetail::find($id);
$this->latitude = $dg->delivery_lat;
$this->longitude = $dg->delivery_long;
$this->render();
}
You could create another method as well if this is a child component:
// Parent livewire component
public function reRenderParent()
{
$this->render();
}
Calling it in the child component:
$this->emit('reRenderParent');
Reinitializing a select2
$(document).ready(function() {
window.initSelectDrop=()=>{
$('#salesperson_id').select2({
placeholder: '{{ __('locale.Select ....') }}',
allowClear: true});
}
initSelectDrop();
$('#salesperson_id').on('change', function (e) {
livewire.emit('salesperson_id', e.target.value)
});
window.livewire.on('select2',()=>{
initSelectDrop();
});
});

Related

Ionic2: how to catch events from within a Modal component (created from ModalController)?

Is there a way to catch local events emitted from within a Modal component (created with ModalController) without dismissing, and not have to use the global Events or a service?
The Angular way to do this is to use listen from Renderer, but I don't see how to get the proper reference to the component instance in this case.
MyComponent.ts
...
export class MyComponent {
#Output() myAwesomeEvent = new EventEmitter<string>();
fireEvent() {
this.myAwesomeEvent.emit('payload');
}
}
Parent.ts
...
const modal = this.modalCtrl.create(MyComponent);
// how do I catch 'myAwesomeEvent' emitted from within MyComponent?
...
IONIC version 4 this may be a workaround? (seems work fine in my app)
let eventEmitter= new EventEmitter();
eventEmitter.subscribe(res=>{
console.log("emitterResult", res)
});
const modal = await this.modalCtrl.create({
component: MyComponent,
componentProps: {
clickFavorite: eventEmitter
}
});
myComponent:
export class MyComponent{
#Output() clickFavorite= new EventEmitter<any>();
favorite(evt){
this.clickFavorite.emit("OK");}
}
}
Access the instance property in modal.
const modal = this.modalCtrl.create(MyComponent);
modal.didEnter.subscribe(() => {
modal.instance.myAwesomeEvent.subscribe(....)
});
Ionic Version 3:
this.modalCtrl.create(MyComponent).present().then((result) =>{
result.instance.myAwesomeEvent.subscribe(....)
});
Ionic 5 +
Create an event emitter and add it in the componentProps attribute of the modal.
Then, in the modal component, add the #Output decorator on this event.
Subscribe to this event in the modal.present() promise.
const modal = await this.modalCtrl.create({
component: ModalComponent,
cssClass: 'custom-modal-class-2',
componentProps: { modalActionObserver: this.modalActionObserver, ActionEvent: new EventEmitter<any>() },
backdropDismiss: true,
initialBreakpoint: 0.6,
breakpoints: [0, 0.25, 0.5, 0.6, 0.7, 1],
});
modal.present().then((result: any) => {
modal.componentProps.ActionEvent.subscribe({
next: (data) => {
//do some action here
}
});
export class ModalComponent implements OnInit {
#Output() ActionEvent
}

Angular2. How to unit test a component with dynamically created html

I have created a virtual list component, where I only render the visible lines.
When creating unit tests, I can test the view while adding elements, but when I remove or change elements then the 'fixture.debugElement' still returns the previous count.
I have created this small test component which shows the problem
The component
class TestComponent {
#ViewChild('view') view: ElementRef;
constructor(public ngRenderer: Renderer) {
}
public add(text: string): void {
let parentelm = this.view.nativeElement;
let element = this.ngRenderer.createElement(parentelm, 'div');
this.ngRenderer.setText(element, text);
}
public remove(index: number): void {
let elm: HTMLElement = this.view.nativeElement;
let child = elm.children[index];
elm.removeChild(child);
}
}
and the test
describe('test component', () => {
let fixture: ComponentFixture<TestComponent>;
let component: TestComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestComponent],
});
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
});
it('add and remove divs', () => {
component.add('item1');
component.add('item2');
let content = fixture.debugElement.query( (elm: DebugElement) => { return elm.attributes['id'] === 'list'; });
expect(content.children.length).toBe(2);
component.add('item3');
expect(content.children.length).toBe(3); // <-- this works
component.remove(1);
fixture.detectChanges();
expect(content.children.length).toBe(2); // <-- this fails
});
});
When checking the browser, then of course the view only contains 'item1' and 'item3'
How can I force an update of the debug element ?
Edit:
I see the fixture contains the native element.
If I add this
let elm = <HTMLElement>fixture.elementRef.nativeElement;
console.log(elm.innerHTML);
Then I see the correct html
'<div id="list"><div>item1</div><div>item3</div></div>'
So maybe the solution is to iterate native elements instead of using the debugElement ?

Angular2 testing with Jasmine, mouseenter/mouseleave-test

I've got a HighlightDirective which does highlight if the mouse enters an area, like:
#Directive({
selector: '[myHighlight]',
host: {
'(mouseenter)': 'onMouseEnter()',
'(mouseleave)': 'onMouseLeave()'
}
})
export class HighlightDirective {
private _defaultColor = 'Gainsboro';
private el: HTMLElement;
constructor(el: ElementRef) { this.el = el.nativeElement; }
#Input('myHighlight') highlightColor: string;
onMouseEnter() { this.highlight(this.highlightColor || this._defaultColor); }
onMouseLeave() { this.highlight(null); }
private highlight(color:string) {
this.el.style.backgroundColor = color;
}
}
Now I want to test, if the (right) methods are called on event. So something like this:
it('Check if item will be highlighted', inject( [TestComponentBuilder], (_tcb: TestComponentBuilder) => {
return _tcb
.createAsync(TestHighlight)
.then( (fixture) => {
fixture.detectChanges();
let element = fixture.nativeElement;
let component = fixture.componentInstance;
spyOn(component, 'onMouseEnter');
let div = element.querySelector('div');
div.mouseenter();
expect(component.onMouseEnter).toHaveBeenCalled();
});
}));
With the testclass:
#Component({
template: `<div myHighlight (mouseenter)='onMouseEnter()' (mouseleave)='onMouseLeave()'></div>`,
directives: [HighlightDirective]
})
class TestHighlight {
onMouseEnter() {
}
onMouseLeave() {
}
}
Now, I've got the message:
Failed: div.mouseenter is not a function
So, does anyone know, which is the right function (if it exists)? I've already tried using click()..
Thanks!
Instead of
div.mouseenter();
this should work:
let event = new Event('mouseenter');
div.dispatchEvent(event);
additional info to gunter's answer, you need to send additional parameter to the Event. Or it won't trigger.
Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Event/composed
let event = new Event('mouseenter', {composed: true});
would be the correct way of defining the event for the HTMLElement to invoke the Event.
Additionally as well, I had missed the following from the create component:
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // <<< THIS
If you do it will appear like the test is working, but by using coverage, you will find the event is not triggered.
A nasty issue to spot.

How do I send a object into the Jquery $('calendar') selector from outside

In the below code, in the didInsertElement, I want to send myController object in to the JQuery Selector ('#calendar').How can I do this. Is it possible to do this. This might be easy. Any one please
(function () {
App.EventDisplayCalendarDisplayView = Ember.View.extend({
didInsertElement: function () {
//I got the controller object here, now I want to pass this in to the JQuery calendar selector below.
// How to do this
var myController = this.get('controller');
$('#calendar').fullCalendar({
weekends: true,
events: this.get('controller'),
dayClick: function(start, allDay, jsEvent, view) {
//I want to access the controller here how to do this.
var controller = myController; //This does not work.
},
eventLimit: true, // for all non-agenda views
views: {
agenda: {
eventLimit: 6 // adjust to 6 only for agendaWeek/agendaDay
}
},
eventClick: function(xEvent, jsEvent, view) {
debugger;
alert("Title: " + xEvent.title //Get the event title
+ "\n StartTime: " + xEvent.start //Get the event start date
+ "\n EndTime: " + xEvent.end //Get the event end date
);
console.log(xEvent); //See your console for all event properties/objects
}
});
},
willDestroyElement: function () {
}
});
}());
Look into calling the function with .bind(variable): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

ReactJS modify parent state from child component

I'm trying to remove an item from my state array when clicked. At the moment I have an onclick listener which calls a function passed into the props. However I get a warning: bind(): React component methods may only be bound to the component instance. See App... and it does not remove the item.
Thanks for any help regarding this issue! It has pretty much ground my progress to a halt.
(function (React) {
var data = [
'Go to work',
'Play Albion Online',
'Keep learning React'
]
var App = React.createClass({
getInitialState: function () {
return {data: []}
},
componentWillMount: function () {
this.state.data = data;
},
removeItem: function (i) {
console.log(i);
},
render: function () {
return (
<ToDoList onRemoveItem={this.removeItem} tasks={this.state.data} />
)
}
});
var ToDoList = React.createClass({
render: function () {
var scope = this;
var tasks = this.props.tasks.map(function (task, i) {
return <ToDo onClick={scope.props.onRemoveItem.bind(this, i)} key={task} task={task} />
});
return (
<ul>
{tasks}
</ul>
)
}
});
var ToDo = React.createClass({
render: function () {
return (
<li>{this.props.task}</li>
)
}
});
React.render(<App />, document.getElementById('example'));
})(React);
React actually auto-binds methods to the current component:
http://facebook.github.io/react/blog/2013/07/02/react-v0-4-autobind-by-default.html
In the TodoList component, rather than:
scope.props.onRemoveItem.bind(this, i)
Try:
scope.props.onRemoveItem.bind(null, i)
By providing null instead of this you'll allow React to do its own thing. Also you need to actually use the onClick handler:
<li onClick={this.props.onClick}>{this.props.task}</li>