I’m trying to create a new dataset type Powerapps Component (PCF). For the moment I am using it to display a view of the records that are available in an entity in Microsoft Dynamics CRM.
I wish to make the view sort itself when I click on the grid column headers (in a similar way that the default CRM grid view does). I'm trying to figure out how to apply a sort to the dataset so that I can refresh it as indicated by the documentation for the dataset.refresh() function:
Refreshes the dataset based on filters, sorting, linking, new column.
New data will be pushed to control in another 'updateView' cycle.
The dataset object does have a “sorting” property, but changing its value and then refreshing the dataset doesn’t seem to have any effect. After the refresh, the sorting property reverts to the value it had before I changed it.
In short, the click handler for the grid header does something like the following bit of code. The refresh gets done and my updateView() function gets called as expected but the sorting was not applied.
dataset.sorting = [{name: 'createdon', sortDirection: 1}];
dataset.refresh();
Any help on getting the dataset sorting to work would be appreciated.
I've been experimenting with PowerApps Component Framework a little bit recently and I can confirm that the following code won't be working:
dataSet.sorting = [ { name: "columnName", sortDirection: 0 } ];
However, I managed to get this one working for me:
dataSet.sorting.pop(); // you may want to clean up the whole collection
dataSet.sorting.push({ name: "columnName", sortDirection: 0 });
I haven't really figured out the reason of this behavior. The sorting array may be implemented as some form of observable collection in the background.
I hope this will guide you to a functioning solution.
The documentation is pretty abysmal here, but here is my best guess from putting a few different pieces of information together.
TLDR: I think there is some kind of extra method that needs to be called on the .sorting property, but I can't find out what it is called. Maybe something like:
dataset.sorting.setSorting({name: 'createdon', sortDirection: 1});
I think you're going to have to try a bunch of likely method names and see what works.
Background and links:
The only reference I could find to dataset.sorting was from here:
In this preview for canvas apps, only a limited set of filtering and sortStatus methods are supported. Filter and sort can be applied to dataset on primary type columns except for the GUID. Filter and sorting can be applied in the same way as in model-driven apps.To retrieve the dataset with filtering and sorting information, call
the methods in context.parameters.[dataset_property_name].filtering
and context.parameters.[dataset_property_name].sorting, then invoke
the context.parameters.[dataset_property_name].refresh().
So it seems that the .filtering and .sorting properties are handled similarly, and that there are some methods attached to them, and only some are supported. That is about as vague as they could make it...
I did find an example of how .filtering is used:
_context.parameters.sampleDataset.filtering.setFilter({
conditions: conditionArray,
filterOperator: 1, // Or
});
There is a brief reference to .setFilter() in the docs, as well as FilterExpression
There is a SortStatus reference, but it doesn't have any corresponding methods explicitly called out. It is possible that this is not yet a supported feature in the public preview, or the documentation is lacking and the name and syntax of the method you need to call on .sorting is not yet documented.
{
"nodes":[{"name":"1","group":5},{"name":"2","group":5},{"name":"3","group":5},{"name":"4","group":0}],
"links":[{"source":1,"target":2,"event_time":1}]
}
So I have this JSON object where I would like to delete the nodes which have no links. For this I'd have to remove the nodes from the "nodes" array and then adjust all indexes in "links", this seems computationally arduous.
mbostock example <- This is an example to use js objects instead of indexes. I therefore tried using
{
"nodes":[{"name":"1","group":5},{"name":"2","group":5},{"name":"3","group":5},{"name":"4","group":0}],
"links":[{"source":{"name":"2","group":5},"target":{"name":"3","group":5},"event_time":1}]
}
but that didn't work either. I'm using a large json file so it wouldn't be optimal to instantiate objects as I go along.
Is there a way to do this?
I'm new to js and D3js.
Thanks!
After reading the documentation about the second parameter in knockout applyBindins, I understand the reason behind it:
Optionally, you can pass a second parameter to define which part of
the document you want to search for data-bind attributes. For example,
ko.applyBindings(myViewModel,
document.getElementById('someElementId')). This restricts the
activation to the element with ID someElementId and its descendants,
which is useful if you want to have multiple view models and associate
each with a different region of the page.
But I have not seen anything about performance. My thoughts (which are based on nothing) are that it makes sense that ko bindings will work faster if to restring the binding not to the whole document, but to a small part of it.
So does it make sense to use ko.applyBindings(myViewModel, $('#someElementId')[0]) without having multiple view models just for the sake of performance. (I heard about Mr. Knuth, so it would be nice to refrain from optimization citation).
applyBindings is a thin wrapper over applyBindingsToNodeAndDescendantsInternal (which is where ALL the magic happens) and if you don't supply a node it uses window.document.body
There is no difference between calling applyBindings(viewModel) and applyBindings(viewMode,rootNode) unless you have a very large DOM and only want to bind a small fraction. In this case use the second parameter and Knockout will have a lot less to scan on the initial setup.
Once the bindings are in place they are reacting locally to observable changes, unlike a framework like AngularJS that can potential scan the entire DOM for changes. The root node is irrelevant at this point.
ko.applyBindings = function (viewModel, rootNode) {
if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
};
This question is about load data embedded into DOM structure.
I am using jQuery2, but the question is valid for any other framework or single Javascript code.
There are two scenarios:
When the data is load once (with the page), no "refresh data" is need.
When data is refreshed by some event.
The average performance can be changed with either one or other
Suppose a typical case of scenario-2, where a page fragment must be reloaded, with new HTML and new data. So, the $('#myDiv').load('newHtmlFragment') will be used any way... And, for jQuery programmer, using AJAX, there are two ways to load an "DOM-based data":
by HTML: expressing all data into the "newHtmlFragment" HTML. Suppose many paragraphs, each like <p id="someId" data-X="someContent">...more content</p>. There are some "verbose overhead" for each data-X1="contentX1" data-X2="contentX2" ..., and is not elegant for webservice script if it is not an XHTML-oriented one (I am using PHP, my data is an array, and I preffer to use json_encode).
by jQuery evaluation: using the same $('#myDiv').load('newHtmlFragment') only for <p id="someId">...more content</p>, with no data-X. A second AJAX load an jQuery script like $('#someId').data(...) and evaluate it. So this is an overhead, for node-selection and data-inclusion, but with big item-data, each data can be enconded by JSON.
by pure JSON: similar to "by jQuery", but the second AJAX load an JSON object like var ALLDATA={'someId1':{...}, 'someId2':{...}, ...}. So this is an overhead for a static function that executes something like $('#myDiv p').each(function(){... foreach ... $(this).data('x',ALLDATA[id]['x']);}) retrive selection, but with big data, all data can be enconded by JSON.
The question: what the best choice? It depends on scenarios or another context parameter? There are signfificative performance tradeoffs?
PS: a complete answer needs to address the issue of performance... If no significative performance differences, the best choice relies on "best programming style" and software engineering considerations.
More context, if you need as reference to answer. My practical problem is at scenario-1, and I am using the second choice, "by jQuery script", executing:
$('#someId1').data({'bbox':[201733.2,7559711.5,202469.4,7560794.9],'2011-07':[3,6],'2011-08':[2,3],'2011-10':[4,4],'2012-01':[1,2],'2012-02':[12,12],'2012-03':[3,6],'2012-04':[6,12],'2012-05':[3,4],'2012-06':[2,4],'2012-07':[3,5],'2012-08':[10,11],'2012-09':[7,10],'2012-10':[1,2],'2012-12':[2,2],'2013-01':[6,10],'2013-02':[19,26],'2013-03':[2,4],'2013-04':[5,8],'2013-05':[4,5],'2013-06':[4,4]});
$('#someId2').data({'bbox':[197131.7,7564525.9,198932.0,7565798.1],'2011-07':[39,51],'2011-08':[2,3],'2011-09':[4,5],'2011-10':[13,14],'2011-11':[40,42],'2011-12':[21,25],'2012-01':[10,11],'2012-02':[26,31],'2012-03':[27,35],'2012-04':[8,10],'2012-05':[24,36],'2012-06':[4,7],'2012-07':[25,30],'2012-08':[9,11],'2012-09':[42,52],'2012-10':[4,7],'2012-11':[17,22],'2012-12':[7,8],'2013-01':[21,25],'2013-02':[5,8],'2013-03':[8,11],'2013-04':[28,40],'2013-05':[55,63],'2013-06':[1,1]});
$('#...').data(...); ... more 50 similar lines...
This question can be discussed from different aspects. Two that I can think of right now would be software engineering and end-user experience. A comprehensive solution covering first can also cover the later but as usually it's not possible to come up with such a solution (due to its cost) these two hardly overlap.
Software engineering point of view
In this POV it is strongly suggested that different parts of the system to be as isolated as possible. This means you better postpone the marriage of data and view as late as you can. It helps you to divide your developers into two separate groups; those who know server-side programming and have no idea how HTML (or any other interface layer technology) works and those who are solely experienced on HTML and Javascript. Just this division alone is a blessing for management and it helps greatly in big projects where teamwork is essential. It also helps the maintenance and expansion of the system, all the things software engineering aims at.
User experience point of view
As good as the previous solution sounds, it comes with (solvable) drawbacks. As you mentioned in your question, if we are to load view and data separately, it elevates the number of requests we have to send to server to retrieve them. It imposes two problems, first the overhead that comes with each request and second the delay user has to wait for each request to be responded. The second is more obvious so let's start with that. With all the advances to the Internet and bandwidths, yet our users' exceeding expectations enforce us to consider this delay. One way to reduce the number of requests would be your first choice: data within HTML fragments. Multiple number of requests also has an overhead problem as well. This can be explained by HTTP protocol's handshake (both on client-side and server-side) and by the fact that each request will lead to loading the session on server which in a large scale could be pretty considerable. So again your first option could be the answer to this problem.
Tie breaker
Having both sides of the story said, what then? The ultimate solution is a combination of both where data and view are married on client but they are downloaded at the same time. To be honest I don't know of such a library. But the principle is simple, you need a mechanism to package data and empty HTML fragments within the same response and combine them into what user will see on client. This solution is costy (to implement) but it is sort of the cost that once paid you can benefit from it for a life time.
It depends on how you are going to use the data that is stored. Consider this example:
Example
You have 300 items in a database (say server access logs of the last 300 days). Now you want to display 300 <div> tags, each tag representing one database-item.
Now there are 2 options to do this:
<div data-stat1="stat1" data-stat2="stat2" data-stat3="stat3">(...)</div>
<!-- again, this is repeated 300 times -->
<script>
// Example on how to show "stat1" value in all <div>s
function showStat1() {
for(var i=1; i<=300; i+= 1) {
var theID = '#id-' + i;
jQuery(theID).text(jQuery(theID).data('stat1'));
}
}
</script>
OR
<div id="id-1">(...)</div>
<!-- repeat this 300 times, for all DB items -->
<script>
data = { // JSON data which is displayed in the <div> tags
'1': ['stat1', 'stat2', 'stat3'],
// same for all 300 items
}
// Example on how to show "stat1" value in all <div>s
function showStat1() {
for(var i=1; i<=300; i+= 1) {
var theID = '#id-' + i;
jQuery(theID).text(data[i][0]);
}
}
</script>
Which scenario is better?
Case 1:
The data is directly coded into the DOM elements, which makes this one an easy to implement solution. You can see in my examples that the first code block takes a lot less code to generate and the code is less complex.
This solution is very powerful, when you want to store data that is directly related to an DOM element (as you do not have to create a logical connection between JSON and DOM): It is very simple to access data for the correct element.
However, your main concern is performance - this is NOT the way to go. Because every time you access data, you have to first select the correct DOM element and attribute via javascript, which takes considerable amount of time. So the simplicity costs you a lot of performance overhead when you want to read/write data in the element.
Case 2:
This scenario very cleanly separates the DISPLAY from the DATA storage. It has major advantages compared to the first case.
A) Data should not be mingled with the display elements - imagine you want to switch from <div> to <table> and suddenly you have to rewrite all javascript to correctly select the correct table cells
B) Data is directly accessible without traversing the DOM tree. Imagine you want to calculate an average sum of all values. In first case you need to loop all DOM elements and read value from them. In the second you simply loop a normal array
C) The data can be loaded or refreshed via ajax. You only transfer the JSON object but not all the HTML stuff that is required for displaying the data
D) Performance is way better, mostly because of the above mentioned points. Javascript is a lot better in handling simple arrays or (not too complex) JSON objects than it is in filtering data out of the DOM tree.
In general this solution is more than twice as fast as the first case. You will also discover - even though it is not obvious - that the second case is also easier to code and maintain! The code simply is easier to read and understand, as you clearly separate the data from the UI elements...
Performance comparison
You can compare the two solutions on this JSPerf scenario:
http://jsperf.com/performance-on-data-storage
Taking it further
For implementation of the second case I generally use this approach:
I generate the HTML code which will serve as the UI. It often happens that I have to generate HTML via javascript, but now I assume that the DOM tree will not change after the page is loaded
At the end of the HTML I include a tag with a JSON object for initial page display
Via jQuery onReady event I then parse the JSON object and update the UI elements as required (e.g. populating the table with data)
When data is loaded dynamically I simply transfer a new JSON object with the new data and use exact the same javascript function as in step 3 to display the new results.
Example of the HTML file:
<div>ID: <span class="the-id">-</span></div>
<div>Date: <span class="the-date">-</span></div>
<div>Total page hits: <span class="the-value">-</span></div>
<button type="button" class="refresh">Load new data</button>
<script src="my-function.js"></script>
<script>
function initial_data() {
return {"id":"1", "date":"2013-07-30", "hits":"1583"};
}
</script>
The "my-function.js" file:
jQuery(function initialize_ui() {
// Initialize the global variables we will use in the app
window.my_data = initial_data();
window.app = {};
app.the_id = jQuery('.the-id');
app.the_date = jQuery('.the-date');
app.the_value = jQuery('.the-value');
app.btn_refresh = jQuery('.refresh');
// Add event handler: When user clicks refresh button then load new data
app.btn_refresh.click(refresh_data);
// Display the initial data
render_data();
});
function render_data() {
app.the_id.text(my_data.id);
app.the_date.text(my_data.date);
app.the_value.text(my_data.hits);
}
function refresh_data() {
// For example fetch and display the values for date 2013-07-29
jQuery.post(url, {"date":"2013-07-29"}, function(text) {
my_data = jQuery.parseJSON(text);
render_data();
});
}
I did not test this code. Also there is crucial error handling and other optimization missing. But it helps to illustrate the concepts that I try to describe
I'm loading data using jQuery (AJAX), which is then being loaded into a table (so this takes place after page load).
In each table row there is a 'select' link allowing users to select a row from the table. I then need to grab the information in this row and put it into a form further down the page.
$('#selection_table').on('click', '.select_link', function() {
$('#booking_address').text = $(this).closest('.address').text();
$('#booking_rate').text = $(this).closest('.rate').val();
});
As I understand it, the 'closest' function traverses up the DOM tree so since my link is in the last cell of each row, it should get the elements 'address' and 'rate from the previous row (the classes are assigned to the correct cells).
I've tried debugging myself using quick and dirty 'alert($(this).closest(etc...' in many variations, but nothing seems to work.
Do I need to do something differently to target data that was loaded after the original page load? where am I going wrong?
You are making wrong assumptions about .closest() and how .text() works. Please make a habit of studying the documentation when in doubt, it gives clear descriptions and examples on how to use jQuery's features.
.closest() will traverse the parents of the given element, trying to match the selector you have provided it. If your .select_link is not "inside" .address, your code will not work.
Also, .text() is a method, not a property (in the semantical way, because methods are in fact properties in Javascript). x.text = 1; simply overrides the method on this element, which is not a good idea, you want to invoke the method: x.text(1);.
Something along these lines might work:
var t = $(this).closest('tr').find('.address').text();
$('#booking_address').text(t);
If #booking_address is a form element, use .val() on it instead.
If it does not work, please provide the HTML structure you are using (edit your question, use jsFiddle or a similar service) and I will help you. When asking questions like this, it is a good habit anyways to provide the relevant HTML structure.
You can try using parent() and find() functions and locate the data directly, the amount of parent() and find() methods depends on your HTML.
Ex. to get previous row data that would be
$('#selection_table').on('click', '.select_link', function(){
$('#booking_address').text = $(this).parent().parent().prev().find('.address').text();
});
Where parent stands for parent element (tr), then prev() as previous row and find finds the element.
Is there a demo of the code somewhere? Check when are you calling the code. It should be after the 'success' of AJAX call.