Accessing listview index in an extensible QML application - javascript

I'm doing an extensible QML application, it means that some of the components are loaded according to the "plugins" loaded on the application.
One of the situations is the following.
I've a ListView, and some of the elements shown on the ListView delegate are loaded based on the plugins.
To create the component/object I use the functions:
Qt.createComponent and component.createObject
It works great, and I can see and interact with the qml components loaded.
However, for some of the features I need to change the listview index from inside a plugin qml file (that is loaded on a delegated), but the index is not accessible from there, and I get a simple
index is not defined
When trying to.
The code is on github: The extension file is this one: https://github.com/danielfranca/procrastinationkiller/blob/master/extensions/timerTasks/taskRow.qml
The specific part I need to access the index is on the clicked signal of mousearea of element with id playpause.
I also tried finding the ListView element, and calling the function indexAt with the x, y mouse coordinates, but it's always returning 0.
The specific code that loads the component is this one:
Component.onCompleted: {
addTaskLayout.inputObjects = Extensions.createExtensionComponent("extraInput.qml", addTaskLayout);
}
And this function is a javascript function that is in this file: https://github.com/danielfranca/procrastinationkiller/blob/master/extensions.js
Let me know if you need more details, and I would love to understand why QML don't expose the index to loaded components and why it can't find the index even with x,y coordinates.
I'm using Qt5.4, Ubuntu 14.10, Qt Creator 3.3.1

The solution is simpler than I expected.
The best way seems to be sending the index as a parameter when creating the component.
In my case the call became:
Extensions.createExtensionComponent("taskRow.qml", row, {"model":tasksModel.get(index), "index": index});
And in my plugin component I create a property with the name index as follow:
property var index: null
Now in my extension function I expect an object with a variable number of properties, and I set it in the creation of the qml element.

Related

Reverse Dom traversing

I started to learn JavaScript and I am creating a navigation component in svelte and needed to add some sort of CSS visualization when there is a dropdown multiple levels deep. so I can see which parents nodes are connected with my "current-item" CSS class.
the visualization I use for this project is a color.
I came up with this logic:
https://codepen.io/Digi4Care/pen/YzaJbdW
The logic I use to determine when I reach the beginning of the node:
"LI" == node?.parentNode?.parentNode?.parentNode?.nodeName
I am wondering if there is another and more efficient way to do this?
Since you're using Svelte - there's the <svelte:self> element to create such a structure recursively. This is the tutorial lesson.
When passing the file object instead of just the name to the File component, the currentFile can then be saved to a store on click. (How do you set the current-menu-item? Based on the url) This value can be used inside the Folder component to set a conditional class, if it's an ancestor.
function isAncestor(files, cF) {
return files.includes(cF) || files.some(file => file.files && isAncestor(file.files, cF))
}
class:current-ancestor={isAncestor(files, $currentFile)}
Here's a REPL with the complete example

Activate a LoadingMask for a View from a Store method in ExtJs without coupling

First of all I know how to set a LoadingMask for a component but have a problem with the uncoupling of the system I am making so I am just looking for a hint/idea.
I am using a MVVC architecture and in the View I have a Container with several Components in it, one of which is a Grid.Panel. The grid is bound to a store and has an event that when fired calls a method of the store. The following code happens in the ViewController:
functionForEvent() {
var store = getStoreForThisGrid();
store.update(Ext.getBody());
}
What happens now is the update() method makes a request to a server, that updates the store itself and the view component, and I need the loading mask during that time. How I handle the situation right now is I pass Ext.getBody() (or a DOM Element representation of a specific component) to the method and it deals with that reference. This function part of the store that is attached to the Grid and resides in the Store:
update : function (el) {
el.mask();
makeRequest();
el.unmask();
}
What I am looking for is another way (Pattern maybe if such exists for JavaScript) to access the View component from the Store instead of passing it around because that does not seem like a good practice and couples the system.
Since I come from a Java background I would have used the Observer pattern but cannot find how to apply this in JS.

Load knockoutjs component using javascript

What's the best way to load a ko component with JavaScript code instead of defining a custom element in html? I tried with ko.components.defaultLoader.load but my component constructor does not hit.
I double checked and the component appears to be registered.
I believe what you are looking for is function ko.components.get(componentName, callback). What this method does is ask the component loaders to resolve the component name until it finds one. If it doesn't find one, it will call callback(null). If it does fine one, it will call callback(componentDefinition), where componentDefinition is the object used to register the component, like { viewmodel: ..., template: ...}.
As far as I can tell, there isn't a ready made function which returns a "working" component. What you have to do after getting the componentDefinition object is something like:
convert the template into a DOM element
instantiate the viewmodel (if defined)
bind the viewmodel to the DOM element
Note that this is not straight away because templates and view models can be defined in several ways.
I recommend looking at https://github.com/knockout/knockout/blob/master/src/components/componentBinding.js and see how it's done here (from line 38).
I hope this works for you, otherwise you could consider other options, like dynamically creating a div element in code with a component binding where the component name and parameters are bound to properties of a view model. Then bind this view model to the div element you just created. This should work "code only" which much less code than the other route.

GeoJSON layer does not get recreated when rendered using EmberJS's 'link-to' helper

I am trying to render a LeafletJS map where the colours of the states in the map are dependent on a global parameter that is set in the appropriate Ember route. The setting of the parameter is not the issue but rather the (re)creation of the geoJson layer. When hitting the URL for the first time or when reloading the page the correct map is created, however when the page is rendered using Ember's 'link-to' helper, the map still holds the state colours of the previous page.
drawAll: function() {
var that = this;
Ember.$.ajax('/data/sa_provinces.json').then( function(data){
Frontend.globalPaths = data;
that.get('store').findAll('province').then(function(provinces) {
provinces.forEach(function(province) {
var provinceGeoJSON = window.L.geoJson( province.get('dataFromJSON'),
{ style: province.get('geoJSONStyle'),
province: province,
onEachFeature: province.get('onEachFeature') });
province.set('geo_json', provinceGeoJSON);
provinceGeoJSON.addTo(Frontend.map);
window.province = province;
});
});
});
}.property('drawAll')
This drawAll function is located within a Ember controller and is called from an Ember template. The functions dataFromJSON, geoJSONStyle and onEachFeature are all called the first time a page is called or when the page is refreshed but not when the page is rendered using the Ember's 'link-to' helper. Neither are they called when the URL is entered manually.
If anyone has any ideas or experience with LeafletJS and/or Ember I would really appreciate your help. Thanks in advance, Greg.
The first issue I notice is that drawAll is a computed property, not a function - you seem to be confusing computed properties and functions.
http://emberjs.com/guides/object-model/computed-properties/
Ember computed properties are more like normal attributes that observe other variables, and recompute when those variables change. The property() method after the function declaration changes it into a computed property and specifies which variables the property depends on. On the last line you're specifying that drawAll observes itself, which doesn't make much sense.
You can't call functions from handlebars templates - you can only access properties. So you can access a property, with the side effect of causing that property's function to be called.
If you want just a function that is called as soon as the template loads, you can implement the didInsertElement function on that templates corresponding view, and the contents of the didInsertElement function will run when the template loads.
If you want a property that recomputes based on some conditions changing, you should change the last line to specify which conditions it is observing.
I can't be sure without more info about the template and controller you're using, but for your current use case it looks like you just want a function that runs whenever the template is inserted, so changing the drawAll to an actual function (by removing the .property('drawAll)) and calling it from didInsertElement of the corresponding view will rerun it every time the controller is inserted. Like:
didInsertElement: function() {
this.drawAll()
}
(You need to have created a view that corresponds to the controller in this context)

Missing view.context or templateContext in an Ember event handler

I'm trying to push the object that populated a view into an array, but the reference is somehow getting lost. I've got an Ember view, with a defined eventManager:
FrontLine.NewProductButton = Em.View.extend({
tagName: 'button',
classNames: ['addtl_product',],
templateName: 'product-button',
eventManager: Ember.Object.create({
click: function(event, view) {
FrontLine.ProductsController.toggleProductToCustomer(event, view);
}
})
})
That view renders a bunch of buttons that are rendered with properties that come from objects in the ProductsController using the #each helper. That part works great. And when I click on any of those buttons, the click event is firing and doing whatever I ask, including successfully calling the handler function (toggleProductToCustomer) I've designated from my ProductsController:
FrontLine.ProductsController = Em.ArrayController.create({
content: [],
newProduct: function(productLiteral) {
this.pushObject(productLiteral);
},
toggleProductToCustomer: function(event, view){
FrontLine.CustomersController.currentCustomer.productSetAdditional.pushObject(view.context);
}
});
I'm trying to use that function to push the object whose properties populated that view into an array. Another place in my app (a simple search field), that works perfectly well, using pushObject(view.context). Here, however, all that gets pushed into the array is undefined. I tried using view.templateContext instead, but that doesn't work any better. When I try console.log-ing the button's view object from inside those functions, I get what I'd expect:
<(subclass of FrontLine.NewProductButton):ember623>
But either view.context or view.templateContext return undefined. How do I access the object I'm after, so I can add it to my array?
The simple answer is that it was one letter's difference:
view.content
or:
view.get('content')
provides the source object in that particular situation, rather than view.context.
(My only real challenge with Ember so far is that accessors for objects and properties vary so much from situation to situation, and there's no real documentation for that. Sometimes the object is at view.context, sometimes it's at view.content, sometimes _parentView.content, etc., etc. It would be awesome if there were a chart with the umpteen different syntaxes for accessing the same data, depending on which particular aperture you're reaching through to get it. I'm still discovering them...)

Categories

Resources