I am trying to optimise my app for windows 8. I have a WinJS.Binding.List and a page which will display a filtered projection of that list. Every time I access the page the filter will most likely be different so I want to dispose of the list when I leave the page.
Here is my filter:
filteredListViewItems = Data.items.createFiltered(function (item) {
if (item.project === certainProject) {
return item;
};
});
When I leave the page I then call:
filteredListViewItems.dispose();
However if I put a breakpoint inside the function it still runs every time I add an item.
How can I remove this altogether?
Related
In my Typescript/Ionic application, I have infinite scrolling that calls async operation like this:
When the view is first loaded, it calls getData with page = 1, and when the scroll reaches the end of the page it then calls getNextPage, which just increments the page count then directly calls getData. The getData function is as follows:
getData() {
this.provider.getData(this.page).subscribe(data => {
if(this.page == 1) {
this.items = data;
this.firstPageData = data;
}
else
for(let d of data)
this.items.push(d);
});
}
I use firstPageData to quickly reload the first page when the user performs an action and returns back to the main view where sees the data items again.
However, when I use firstPageData, it contains all items of the scrolled pages and not only the first page! I tried to debug the code and understand what is going on there but with no luck.
Am I missing something here? Please help.
I have a function that is executed each time a user updates an entry, in order to keep the list of entries up-to-date. The problem I'm running into is that when I run .clearCache() on the index, even though I'm doing it before the actual search function is run, it takes two reloads in order to get the latest updates. It's acting as if it's a reload behind. I have no idea what's causing this, but here is my search function:
search() {
this.results = [];
// Clear the algolia cache
this.auditionsIndex.clearCache();
this.auditionsIndex.search('', options).then(result => {
if(result.hits && result.hits.length > 0) {
this.results = result.hits;
}
// Clear the cache one more time
this.auditionsIndex.clearCache();
});
}
Changing something in an Algolia index happens asynchronously, when you execute something like index.saveObject() the result of the Promise/callback will be an object with taskId. You can then index.waitTask for that task, and send some event to your frontend to let it know to clear the cache and search.
see https://www.algolia.com/doc/api-reference/api-methods/wait-task/#methods
I'm using Sortable to organise lists inside of parent groupings, which themselves are also sortable, similar to the multi example on their demo page, but with text. This works fine and uses code along the lines of:
var globObj = {};
function prepSortCats() {
globObj.subCatsGroup = [];
// Changing parent group order
globObj.sortyMainCats = Sortable.create(catscontainer, {
// options here omitted from example
onUpdate: function( /**Event*/ evt) {
// Send order to database. Works fine.
}
});
// Changing sub list order
globObj.subCatsGroup.forEach.call(document.getElementById('catscontainer').getElementsByClassName('subcatlist'), function(el) {
var sortySubCats = Sortable.create(el, {
// options here from example
onUpdate: function( /**Event*/ evt) {
// Send order to database. Works fine.
}
});
});
}
Which is called when the page loads using:
$(document).ready(function () {
// Sortable
prepSortCats();
});
All good so far. However, the user can introduce new elements into any of the lists (sub or parent). In brief, any new elements added by the user are first added to the database, then the relevant section of the page is refreshed using ajax to pull the updated content from the database and display that. The user sees their newly added items added to one of the existing lists. Ajax call is as follows:
function refreshCategories() {
var loadUrl = "page that pulls lists from database and formats it";
$("#catscontainer")
.html(ajax_load)
.load(loadUrl);
return false;
};
This works fine too. Except, Sortable no longer works. I can't drag any lists. My first thought was to destroy the existing Sortable instances and reinitialize them. Right after I called refreshCategories() I call the following:
if(globObj.sortyMainCats.length !== 0) {
globObj.sortyMainCats.destroy();
}
if(globObj.subCatsGroup.length !== 0) {
var i;
for (i = globObj.subCatsGroup.length - 1; i >= 0; i -= 1) {
globObj.subCatsGroup[i].destroy();
globObj.subCatsGroup.splice(i, 1);
}
}
prepSortCats();
But Sortable still has no effect. I introduced the global object (although controversial) so that I could target the Sortable instances outside their scope but I appear to have overlooked something. Any ideas? Apologies for not providing a working example. As I make various ajax calls to a server, I don't think this is possible here.
Update
I'm clearly misunderstanding some action that's taking place. Well, I should preface that by saying I missed that I could still organise the group/parent lists after reloading a section of the page by ajax with refreshCategories(). This is very much a secondary action to being able to sort the sub lists, which is what I noticed was broken and remains so.
But it did point out that although the entirety of $("#catscontainer") was being replaced with a refreshed version of the lists (and that's all it contains, list elements), Sortable still had some sort of instance running on it. I was under the understanding that it was somehow tied to the elements that were removed. Now I'm a bit more lost on how to get Sortable to either: (a) just start from scratch on the page, performing prepSortCats() as if it was a fresh page load and removing any previous Sortable instance, or (b) getting the remaining Sortable instance, after the ajax call to recognise the added elements.
Update 2
Making some progress.
Through trial and error I've found that right after calling refreshCategories(), calling globObj.sortyMainCats.destroy() is preventing even the group lists from being ordered. Then if I call prepSortCats() after this, I can move them again. But not the sub lists.
This isn't conclusive but it looks like I'm successfully destroying and reinitializing Sortable, which was my goal, but something about the ajax loaded elements isn't working with Sortable.
I was looking for the answer in the wrong place, being sure it was an issue with ajax loaded content and the dom having some inconsistencies with what Sortable expected.
Turns out it was an asynchronous problem. Or, to put it simpler, the section of the page being loaded by ajax wasn't quite ready when Sortable was being asked to be reinitalized.
For anyone having the same trouble, I changed:
$("#catscontainer")
.html(ajax_load)
.load(loadUrl);
to
$("#catscontainer")
.html(ajax_load)
.load(loadUrl, function() {
reinitSortable();
});
where reinitSortable() is just a function that fires off the destroy and prepSortCats() functions similar to how they're displayed above.
I have a table created from an observable array. Table rows contains elements belonging each to one of a set of categories. To filter the table based on categories, there is a row of buttons.
Buttons can be active or inactive, indicated via a CSS class bound via knockout:
<button data-bind="click: filter.filterCategory, css: { filterOn: filter.category.isFiltered() }">Filter</button>
Filtering within the table is done by switching the display state of rows:
<tr data-bind="css: { nonDisplay: !table.category.isDisplayed() }">
</tr>
The click handler mainly sets the values of the two observables, in sequence e.g.
vm.filter.category.isFiltered(true);
vm.table.category.isDisplayed(false);
This works in principle.
The problem is that the indication that the filter button has been selected by the user is not given immediately, but dependent on the execution time of the filtering itself, i.e. the changes to the table.
With larger tables, and especially on mobile, this can mean delays of a couple of seconds.
I can live with the filtering itself taking this long, but the feedback needs to be immediate.
Is there a way to ensure that the change on vm.filter.category.isFiltered gets applied before the longer running change based on vm.table.category.isDisplayed is started?
This seems as an async fail.
You should implement a callback method parameter in the isFiltered method, something like this
var vm = vm || {};
vm.filter = vm.filter || {};
vm.filter.category = (function($){
var that = this;
that.isFiltered = function(booleanValue, callback) {
// Put your primary code here
console.log("this runs first");
// ...when the first code is done
callback();
};
that.isDisplayed = function(booleanValue) {
console.log("this runs second");
};
return that;
})($);
// Implement by stating a method as the second parameter.
vm.filter.category.isFiltered(true, function(){ vm.filter.category.isDisplayed(false); });
This will render
// this runs first
// this runs second
In my Windows 8 JavaScript application, I have a ListView. I need to add either a message or link to a row, depending on what the current user's status is. So I essentially need to show or hide items depending on some flag. How, using the JavaScript API of the ListView, do I parse items at an item level? There is no collection of items on the ListView control per the MSDN, and I need to have access to the data and the item at the row level.
I'm sure I'm missing it somehow, just getting into this....
I'm not completely clear on what your trying to do, but I'll give it a shot.
If you need to conditionally show or hide items (or certain parts of an item) there and a couple of ways you can go.
The first is to create an imperative template render function. First, tell you ListView that its item template is a function with something like myListView.itemTemplate = myCustomFunction. Then write a function like:
function myCustomFunction(itemPromise) {
//you have to return a promise
return itemPromise.then(function (item) {
//get the right item template (declared in your HTML),
//render the item data into it, and return the result
var itemTemplate;
if (item.data.key === "foo")
itemTemplate = q("#fooItemTemplate", element); //return foo template
else if (item.data.key === "bar")
itemTemplate = q("#barItemTemplate", element);
return itemTemplate.winControl.render(item.data);
});
}
If one of the item templates has explicit style code to show or hide part and the other doesn't then you'll get the result you're looking for.
Another way is to wait until the ListView is finished loading and then traverse and manipulate the DOM according to your conditions.
To capture the moment your ListView finishes loading do this:
myListViewControl.onloadingstatechanged = function (e) {
if (myListViewControl.loadingState == "complete") {
...
}
}
The ListView goes through a few loading states as it's loading and the last is "complete". When it's complete, you can use the awesome power of CSS selectors and the new querySelector/querySelectorAll method that ECMAScript 5 gives us to find all of the ListView items like this:
myListView.querySelectorAll(".win-item")
That would return a NodeList of all of the ListView items and you can use your ninja skills in DOM manipulation to have your way with them.
Hope that helps!!
P.S. Check out codeSHOW to learn more HTML/JS dev in Windows 8 (aka.ms/codeshowapp | codeshow.codeplex.com)