How to run a specific method when props changes in Svelte3? - svelte-3

I'm building an autocomplete text field component. We will show popup of items filtered based on what users type. It is going to be async, I will get the details from the server and do some filtering based on the text typed in the field.
So here, I have run this filtering logic whenever I send new data to the component.
I come from angular, there we used to have ngOnChange(). Is there something similar available in svelte3.
Right now, I'm filtering by calling the method from outside by binding bind:this. I don't feel like this is a correct approach.
https://github.com/manojp1988/svelte3-autocomplete/blob/master/dev/App.svelte

Without stores, using a prop
Just using a prop:
export let search = '';
....
$: if (search !== '') { // make it react to changes (in the parent)
doSomeThing(search);
};
Stores
Svelte also has stores. A store is an observable object which can be observed everywhere even beyond you project with RxJS.
Example:
const unsubscribe = search.subscribe(s) => {
doSomeThing(s);
});
onDestroy(unsubscribe);
In another component you can use search.set('Hi');
But looking forward for other solutions to handle these kind of changes in parent <-> child components or calling child Component methods.
From child to parent we can fire events.
But from parent to child ...? we can use a store or Component bind:this or ..? but ....

Related

How to reload a ResourceTable programmatically in Laravel Nova?

I have a custom resource-tool (ledger entry tool) that modifies values of a resource as well as insert additional rows into related resources.
"Account" is the main resources.
"AccountTransaction" and "AccountLog" both get written to when a ledger entry is created. And through events, the account.balance value is updated.
After a successful post of a ledger entry (using Nova.request) in the resource-tool, I would like the new balance value updated in the account detail panel, as well as the new entries in AccountTransaction and AccountLog to be visible.
The simple way would be to simply reload the page, but I am looking for a more elegant solution.
Is it possible to ask these components to refresh themselves from within my resource-tool vue.js component?
Recently had the same issue, until I referred to this block of code
Nova has vuex stores modules, where they have defined storeFilters.
Assigning filters an empty object and then requesting them again "reloads" the resources. Haven't done much more research on this matter, but if you are looking for what I think you are looking for, this should be it.
async reloadResources() {
this.resourceName = this.$router.currentRoute.params.resourceName || this.$router.currentRoute.name;
if (this.resourceName) {
let filters_backup = _.cloneDeep(this.$store.getters[`${this.resourceName}/filters`]);
let filters_to_change = _.cloneDeep(filters_backup);
filters_to_change.push({});
await this.$store.commit(`${this.resourceName}/storeFilters`, filters_to_change);
await this.$store.commit(`${this.resourceName}/storeFilters`, filters_backup);
}
},

Dynamic Tag Management - Storing

We're in the process of moving to DTM implementation. We have several variables that are being defined on page. I understand I can make these variables available in DTM through data elements. Can I simply set up a data elem
So set data elements
%prop1% = s.prop1
%prop2% = s.prop2
etc
And then under global rules set
s.prop1 = %s.prop1%
s.prop2 = %s.prop2%
etc
for every single evar, sprop, event, product so they populate whenever they are set on a particular page. Good idea or terrible idea? It seems like a pretty bulky approach which raises some alarm bells. Another option would be to write something that pushes everything to the datalayer, but that seems like essentially the same approach with a redundant step when they can be grabbed directly.
Basically I want DTM to access any and all variables that are currently being set with on-page code, and my understanding is that in order to do that they must be stored in a data element first. Does anyone have any insight into this?
I use this spec for setting up data layers: Data Layer Standard
We create data elements for each key that we use from the standard data layer. For example, page name is stored here
digitalData.page.pageInfo.pageName
We create a data element and standardize the names to this format "page.pageInfo.pageName"
Within each variable field, you access it with the %page.pageInfo.pageName% notation. Also, within javascript of rule tags, you can use this:
_satellite.getVar('page.pageInfo.pageName')
It's a bit unwieldy at times but it allows you to separate the development of the data layer and tag manager tags completely.
One thing to note, make sure your data layer is complete and loaded before you call the satellite library.
If you are moving from a legacy s_code implementation to DTM, it is a good best practice to remove all existing "on page" code (including the reference to the s_code file) and create a "data layer" that contains the data from the eVars and props on the page. Then DTM can reference the object on the page and you can create data elements that map to variables.
Here's an example of a data layer:
<script type="text/javascript">
DDO = {} // Data Layer Object Created
DDO.specVersion = "1.0";
DDO.pageData = {
"pageName":"My Page Name",
"pageSiteSection":"Home",
"pageType":"Section Front",
"pageHier":"DTM Test|Home|Section Front"
},
DDO.siteData = {
"siteCountry":"us",
"siteRegion":"unknown",
"siteLanguage":"en",
"siteFormat":"Desktop"
}
</script>
The next step would be to create data elements that directly reference the values in the object. For example, if I wanted to create a data element that mapped to the page name element in my data layer I would do the following in DTM:
Create a new data element called "pageName"
Select the type as "JS Object"
In the path field I will reference the path to the page name in my data layer example above - DDO.pageData.pageName
Save the data element
Now this data element can be referenced in any variable field within any rule by simply typing a '%'. DTM will find any existing data elements and you can select them.
I also wrote about a simple script you can add to your implementation to help with your data layer validation.Validate your DTM Data Layer with this simple script
Hope this helps.

Extending entities on a per view basis with breeze.js in SPA

Trying to figure out how to extend entities that I query from breeze.js on a per-view basis in a single page application. Right now breeze is acting as the gate-keeper when it comes to extending (a.k.a materializing) them and I’m wondering what other options are available to allow me to do this. I initially started with knockout’s mapping plugin but found that it refused to handle child collections for some reason so I moved to using breeze’s constructor function and initializer methodology. The problem with this is that you can only define one custom "model" for an entity. I am looking for approaches that would allow a custom "model" of an entity on a per-view basis. I’ve already ruled out multiple managers. Querying meta-data multiple times is a huge unnecessary hit just to get this working.
This diagram visualizes what I’m trying to achieve. Both View 1 and View 2 ultimately query Entity B and both views require their own specific customization of the "model" of Entity B. Since View 1 loads first it’s custom "model" of Entity B "wins" and View 2 doesn’t have the opportunity to customize it. When View 2 eventually runs it’s query, any entities of type B that were already loaded by View 1 will have the custom "model" that View 1 defined which will make View 2 explode during binding. Any entities not already loaded by View 1 will now have View 2's custom "model" which would eventually crash View 1 if it could even get that far down the road. See this post.
My thought was to manually create my own custom "model" for each view that has an Entity observable and I could then iterate over every entity returned from a breeze query and new up this custom "model" and pass in the current item, assigning it to the Entity property. I don't really want to do this because I now have I'll have tons of iteration code everywhere and I'd much rather use knockout's mapping plugin. Pseudo code:
function view1EntityBModel(entity) {
var self = this;
self.Entity = ko.observable(entity);
self.myCustomProperty = ko.observable();
...
}
function view2EntityBModel(entity) {
var self = this;
self.Entity = ko.observable(entity);
self.isExpanded = ko.observable(false);
...
}
I was wondering if there are any other solutions available to achieve this same goal?
Or even better does anyone know how to make the knockout mapping plugin working on child collections?
I think the problem here is that by the time the mapping plugin gets a-hold of the breeze data the Children collection has already been converted into an observable array and the mapping plugin doesn't know that it needs to "call" the Children() property in order to get back a list.
var categoryMapper = {
create: function (options) {
return new categoryModel(options.data);
},
Children: { // this doesn't fire for the children
create: function (options) {
return new categoryModel(options.data);
}
}
}
function categoryModel(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
}
Guessing that you've moved on by now, but thought I'd offer a recommendation for others in a similar position.
Our solution to a similar situation borrows from the breeze.js TempHire sample solution which implements a client side repository/uow pattern. The solution uses an EntityMananagerProvider to manage multiple EntityManagers. The EntityMananagerProvider makes a single call for metadata, which is then used to create new child EntityManagers - satisfying your concern regarding multiple metadata calls. You can then use custom models/uow/repositories to extend the child manager for specific views.

Knockout js registerEvent handler

I'm having a great time playing around with knockout js and have just started to get to grips with adding custom bindingHandlers.
I'm struggling a bit with the update function of a 3rd party jqWidget gauge - I can only get it to animate the first time I update the variable. On each update after that it just sets the value directly.
I don't fully understand ko.utils.registerEventHandler() and what it does although I've seen it in a bunch of other examples. Is this what is causing the animation to break? How do I know which events to register from the 3rd party widget?
For some reason this works fine if I add a jquery ui slider that is also bound to the observable.
You can test this here: set the value a few times to see that it animates the first time and not after that.
http://jsfiddle.net/LkqTU/4531/
When you update the input field, your observable will end up being a string. It looks like the gauge does not like to be updated with a string value, at least after the first time.
So, if you ensure that you are updating it with a number (parseInt, parseFloat, or just + depending on the situation), then it appears to update fine.
Something like:
update: function(element, valueAccessor) {
var gaugeval = parseInt(ko.utils.unwrapObservable(valueAccessor()), 10);
$(element).jqxGauge('value', gaugeval || 0);
}
http://jsfiddle.net/rniemeyer/LkqTU/4532/
You would generally only register event handlers in a scenario like this to react to changes made by a user where you would want to update your view model data. For example, if there was a way for a user to click on the gauge to change the value, then you would want to handle that event and update your view model value accordingly.
I'm answering the
I don't fully understand ko.utils.registerEventHandler() and what it does
part of your question.
registerEventHandler will register your event handler function in a cross-browser compatible way. If you are using jQuery, Knockout will use jQuery's bind function to register the event handler. Otherwise, will use the browser Web API with a consistent behavior across browsers.
You can check it out on the source code.

Dynamically Loading LI's in JQueryMobile 1.0

I've just updated my project from jquerymobile 1.0a1 to version 1.0.
I've encountered a problem with dynamic content. Based on an ajax search I populate an unordered list with list items. Previous the following code refreshed the list so that all the styling appeared correctly:
$('#myContent').find("ul").listview();
$('#myContent').find("ul").listview('refresh');
However as of 1.0 this no longer seems to work.
The list appears but the styling is all wrong and the data-theme on all the elements gets ignored.
Has anyone come across a similar issue with updating and come across the solution.
Updating lists If you add items to a listview, you'll need to call the refresh() method on it to update the styles and create
any nested lists that are added. For example:
$('#mylist').listview('refresh');
Note that the refresh() method only affects new nodes appended to a
list. This is done for performance reasons. Any list items already
enhanced will be ignored by the refresh process. This means that if
you change the contents or attributes on an already enhanced list
item, these won't be reflected. If you want a list item to be updated,
replace it with fresh markup before calling refresh.
http://jquerymobile.com/demos/1.0/docs/lists/docs-lists.html
if #myContent is the listview you can do this:
$('#myContent').listview('refresh');
if #myContent is the page you can do something like this:
$('#myContent').trigger('create');
Create vs. refresh: An important distinction Note that there is an important difference between the create event and refresh method
that some widgets have. The create event is suited for enhancing raw
markup that contains one or more widgets. The refresh method should be
used on existing (already enhanced) widgets that have been manipulated
programmatically and need the UI be updated to match.
For example, if you had a page where you dynamically appended a new
unordered list with data-role=listview attribute after page creation,
triggering create on a parent element of that list would transform it
into a listview styled widget. If more list items were then
programmatically added, calling the listview’s refresh method would
update just those new list items to the enhanced state and leave the
existing list items untouched.
http://jquerymobile.com/demos/1.0/docs/pages/page-scripting.html
What you want can be achieved by replacing your 2 lines of code with the following:
$('#myContent ul').listview('create');
Hope this helps...
I've had this issue. The reason you are getting things all messed up is you are initalizing and refreshing the element multiple times. I noticed I had 2 different functions running that would call .listview('refresh') on the same element. After I took one out the themes and data went back to looking normal. Also are you getting any JS errors?
EDIT:
To be more specific you are calling .listview() somewhere in your code 2 times which is initializing it twice. I would wait to before you page is loaded to run the refresh so you only call it once.
Another thing you could do is check if the element is initialized already or not so you don't do it twice. Just check the element or in some cases the parent to see if the class ui-listview is present.
var element = $('#myContent').find('ul');
if ($(element).hasClass('ui-listview')) {
//Element is already initialized
$(element).listview('refresh');
} else {
//Element has not been initiliazed
$(element).listview().listview('refresh');
}
Just an FYI you can chain those events to look like $('#myContent').find('ul').listview().listview('refresh');
It cand be achived through.
$('#myContent').listview('refresh');
The below snippet shows you to load data from xml and dynamically create a list view.
function loadData()
{
$.ajax({
url:"BirthdayInvitations.xml",
dataType: "xml",
success: function(xml)
{
$(xml).find("event").each(function()
{
$("#mymenu").append('<li>' + this.textContent + ' </li>');
});
$("#mymenu").listview('refresh');
}
});
}
See if this is related to ur question http://www.amitpatil.me/demos/jquery-mobile-twitter-app/ and this one also http://www.amitpatil.me/demos/ipad-online-dictionary-app/
In first example i am using listview('refresh'); method and in second example i am using
$(document).page("destroy").page();

Resources