I have 3 components Map, Field & Section. Map is the parent component. Field & Section are child components.
There is an action called testField in Field component. Inside the test function first I want to trigger an event SaveSection on Section component and then continue other stuff.
// In field component
public function testField(): void
{
// Save section
$this->emitTo('section', 'saveSection');
Log::debug('Testing.....');
}
// In section component
public function saveSection()
{
Log::debug('saveSection+++++');
$this->emitTo('map', 'storeSection', $this->section, $this->sectionIndex);
}
// In map component
public function storeSection(array $section, int $sectionIndex)
{
Log::debug('storeSection-----');
// Store to DB
....
}
But it prints Testing..... before storeSection-----. Is there way I can wait for events to finish before continue.
Hi based on our conversation, I think you would want to go with hooking into Livewire and listening for message processed events.
The first step would be to wrap Log::debug('Testing.....'); in a function like this. The original idea came from #Prospero Livewire show loader when an event is emitted
public function testLog()
{
Log::debug('Testing.....');
}
You might want to tweak this to your satisfaction as this is just a recommendation.
Now you need to prepare your application to stack scripts in the base view right before the closing body tag. eg in app.blade.php like this
<body>
...//Whatever thats before it
#stack('scripts')
</body>
This would help you stack the custom script tag you would define in the component view.
After this you now use the Livewire hook. Do this properly to avoid DOM diffing issues as Livewire would cry tears in your developer console:
<script>
document.addEventListener('livewire:load', function () {
Livewire.hook("message.processed", (message, component) => {
if (message.updateQueue[0].payload.event === "storeSection") {
// I have not implemented it this way so try any of them
//#this is a brilliant decorator that finds the component
#this.emit('testLog') or #this.call('testLog')
}
});
})
</script>
This would show Testing....`` after storeSection``` is processed.
Please do let me know if this does not work as I might have to implement changes.
Related
When it try trigger to updated life hook when property is changed/updated not work
example
...
public function updatedName($name){
dd($this->name);
}
and I find this message from livewire doc.
Please note that mutating a property directly inside a Livewire component class doesn't trigger any of the updating/updated hooks.
Please. do someone can explain in detail this message from https://laravel-livewire.com/docs/2.x/lifecycle-hooks meaning and what should be done instead
The warning means that the Lifecycle Hooks are not called when you update a property inside the PHP component class.
An example usage is to catch when a user updates a property via the wire:model attribute.
class HelloWorld extends Component
{
public $foo;
public function updatedFoo($value)
{
//
}
public function mount()
{
$this->foo = "New Value";
// updatedFoo will NOT be called
}
}
<input type="text" wire:model="foo" />
<!-- Entering text into this field will cause the hook to be called -->
try this
public $name;
public function updatedName($value)
{
// if you want get value
dd($value);
// if you want change name to new value
$this->name = $value
}
I am writing tests in a vue app (using Jest). While testing a certain component, I need to trigger a change event on a checkbox (which I am using BFormCheckbox for).
When I select the checkbox using the selector the actual checkbox evaluates to ('.custom-control-input'), I can get the test below to pass. However, I would like to use the name of the actual component (BFormCheckbox), which I feel would be easier to follow. Is there any way to make this work?
it('is triggered by clicking a phase checkbox', () => {
// I would like to write:
// const phaseCheckbox = wrapper.find(BFormCheckbox);
// However, I can only get the following to work:
const phaseCheckbox = wrapper.find('.custom-control-input');
// this is true for both selectors
expect(phaseCheckbox.exists()).toBe(true);
phaseCheckbox.trigger('change');
// this fails for wrapper.find(BFormCheckbox)
expect(togglePhaseSpy).toHaveBeenCalled();
});
Since the <input type="checkbox"> is nested inside additional HTML markup (as defined by Bootstrap v4), use the following to access the hidden input:
const phaseCheckbox = wrapper.find(BFormCheckbox).find('input')
This will not tie you to using the inner element classname(s), as they do change depending on the rendering style mode of <b-form-checkbox> (i.e. default custom checkbox, switch style checkbox, button style checkbox, or plain mode checkbox).
Jest documentation shows examples of how to do as you are asking.
Component Constructors:
import Foo from '../components/Foo';
const wrapper = mount(<MyComponent />);
expect(wrapper.find(Foo)).to.have.lengthOf(1);
Component Display Name:
const wrapper = mount(<MyComponent />);
expect(wrapper.find('Foo')).to.have.lengthOf(1);
My code:
signup.emblem:
= validating-form onsubmit=(action 'signUp')
= input-field value=username
span {{usernameError}}
validating-form.js:
submit(event) {
console.log(this.get('username') //undefined
this.sendAction('onsubmit')
}
signup.js:
actions: {
signUp() {
console.log(this.get('username')) // value from input
}
}
As you can see the basic idea is some value in input gets validated in validating-form component and then if everything is fine it'll call some controller action or set some properties.
The problem is that apparently this form component isn't bind to properties from controller, even though its child component (input-field) is. Can you tell me what am I doing wrong here?
If I have to bind it explicitely, is there some way to do that with multiple properties at once?
The problem is that the standard input element isn't two-way bound to your username variable. You can bind it quickly using the action and mut helpers.
(example in handlebars, but you should be able to convert to emblem easily enough)
<input value={{username}} onblur={{action (mut username) value='target.value'}}>
This is saying:
on the onblur event
mut(ate) the username
to match the current target.value - which is the value of the input box
You can see evidence of this working in this twiddle
The other option is Input Helpers
I've not used these, as they don't follow the current Ember thinking of Data Down Actions Up, but it should be as simple as:
{{input value=username}}
And this will two-way-bind directly username.
I am building notification feature for my app just like Facebook's notification. I have almost made it work but just unable to observe a computed property.
Here is the scenario:
There are many deals and when a deal is updated(like it's name/ price is changed), the notification is sent through RabbitMQ. The object payload that we send, it has an attribute "status" which could be 'read' or 'unread'.
controller:
notificationsCount: function() {
var notifications = this.get('notifications');
var unreadCount = 0;
for (var i = 0; i < notifications.length; i++) {
if (notifications[i].status == 'unread') {
unreadCount++;
}
}
return unreadCount;
}.property('notifications.[]'),
Here, initially 'notifications' is an empty array. All the notifications coming from RMQ as object payloads goes inside this. This 'unreadCount' is what I want to show kinda like a small badge over the notification icon.
When I click the notification icon, all the notifications' status should change to 'read' from 'unread'.
controller:
action:{
readNotifications: function () {
var notifications = this.get('notifications');
for (var i = 0; i < notifications.length; i++) {
notifications[i].status = 'read';
}
},
}
Through debugging, I found everything is working fine till this point. But what I want is, once the user clicks the notification icon and all the notifications are marked as read, the notificationCount should be set as zero as there are no more any notifications that is unread.
Theoretically, I have to either observe notificationsCount or execute notificationsCount once inside readNotifications action. But I couldn't find a way to do it. If there is any other way, feel free to share.
Thanks in advance.
The short of it is that you should define your notificationsCount computed property to listen to notifications.#each.status instead of notifications.[]. .[] triggers when the array contents change (elements are added or removed), while an .#each.prop triggers when the prop property on any array element changes.
Refer to the relevant Ember.js docs for details on this.
Additionally, you can make your code more concise using NativeArray methods (because, since you are already using the .property() shorthand, you do have prototype extension enabled). Your entire notificationsCount could be written as
notificationsCount: function() {
return this.get('notifications').filterBy('status', 'unread').length;
}.property('notifications.#each.status'),
and your action as
readNotifications: function () {
this.get('notifications').setEach('status', 'read');
},
I have a legacy WebService referenced in a ScriptManager
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="~/AJAX_SERVICE.asmx" />
</Services>
</asp:ScriptManager>
And defined like
<System.Web.Script.Services.ScriptService()> _
Public Class CAjaxService : Inherits System.Web.Services.WebService
<WebMethod(enableSession:=True)> _
Public Sub SomeMethod()
...
End Sub
...
End Class
After that to call the method from JavaScript client code I can simple do
CAjaxService.SomeMethod()
I need to execute this call when user navigates away from the current page, so I placed it into page unload event:
function pageUnload(sender, args) {
CAjaxService.SomeMethod()
}
The problem is - the call is async and page navigates away before call is complete (if I place alert() after the call - it goes thru). I've seen similar problems with jQuery ajax calls (and recommended solution to make a synchronous call) but I am not sure if this is possible in MS Ajax.
What would be the way to execute (and complete) an AJAX call upon user navigating away from current page?
You should attach to the onBeforeUnload event instead of the onUnload event.
The onUnload event actually fires when the first byte of the next page is downloaded. At this time the entire context of the previous page starts to get destroyed, and there's a very low chance that you will be able to create network connections. The best that you could do at this point is set a cookie via JavaScript.
The onBeforeUnload event, however, fires before the request for the next page is made, and you have enough time to make a network call to your server to pass it some information. Make your Ajax call within this method.
I try to reply your requirements I create a simple web service that sleep for 5 seconds
[WebService(Namespace = "http://tempuri.org/")]
[ScriptService]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CAjaxService : System.Web.Services.WebService {
[WebMethod(true)]
public string SomeMethod() {
Thread.Sleep(5000);
return DateTime.Now.ToString(CultureInfo.InvariantCulture);
}
}
I try to call it synchronusly but the only way to do it using the MS Ajax Library is to extends the Sys.Net.XMLHttpExecutor you can see the post
I can make the page to wait in the unload event using jquery and make the ajax call synchronously with this code
<script src="Scripts/jquery-2.0.3.js"></script>
<script>
window.onbeforeunload = function () {
$.ajax({
type: "POST",
url: "CAjaxService.asmx/SomeMethod",
async: false,
});
};
</script>
I hope this will help you
I ended up implementing my own function
CAjaxService.SomeMethodSync = function() {
...
}
where I do a manual synchronous post request. Not the most elegant method, but it works.