SAPUI5: Example for a composite control? - binding

I am searching for a good example of a composite control.
My current problem is, that I plan to bind a simple value (for example a string) that will be reused in some other control inside a composite control.
Following code seems not correct:
metadata : {
properties : {
"head" : {type : "string", defaultValue : ""},
...
},
},
init : function() {
... some control with content ...
content : [
new sap.m.Label({text : this.getHead()})
]
...
My plan to call the composite control would look like this:
var oTemplate = new MyControl({ head : "{Name}" });
Using the template for example in a list.
Binding may work, but because of the fact that I build the control in the "init" part it looks like the property is not initialised and will not be updated automatically.
A further experiment (that will not work):
jQuery.sap.declare("StrangeControl");
sap.m.HBox.extend("StrangeControl", {
metadata : {
properties : {
},
aggregations : {
input : {type : "sap.m.Input", multiple : false},
}
},
// will be called during creation time
init : function() {
sap.m.HBox.prototype.init.call(this);
this.addItem(this.getAggregation("input"));
},
renderer : {},
onAfterRendering : function() {
if (sap.m.HBox.prototype.onAfterRendering!==undefined) {
sap.m.HBox.prototype.onAfterRendering.call(this);
}
}
});
I assume to use the control that way:
new StrangeControl({
input : new sap.m.Input({value : "test"})
})
But during init input is not defined (==null). The mentioned example https://github.com/SAP/openui5/blob/master/src/sap.m/src/sap/m/SelectDialog.js seems to handle the "items" in a different way but for me it is not clear how.
Meanwhile there a documentation exists (at least in OpenUI5beta SDK).
https://openui5.hana.ondemand.com/#/topic/c1512f6ce1454ff1913e3857bad56392
If the link does not work search for "Composite Controls" inside the "DEVELOPER GUIDE" section.

A: Just add your internal control to a hidden aggregation - it will automatically get all the data binding for free, you just have to bind the properties/aggregations of that control accordingly.
B: You could also overwrite the setters of your outer control which then call the setters of the inner control in order to propagate the values.
setHead : function(oValue) {
return this.getAggregation("_myHiddenInnerControl").setValue(oValue);
}
It is still necessary to add the inner control to an aggregation, to avoid memory leaks (else you have to make sure everything is cleaned up in the exit method.

Related

Automatically update a flow from a changes of another flow (StateFlow) Jetpack Compose

I have a StateFlow from which my List composable collects any changes as a State.
private val _people = MutableStateFlow(personDataList())
val people = _people.asStateFlow()
And inside my viewModel, I perform modifications on _people and I verify that people as a read-only StateFlow is also getting updated. I also have to make a copy of the original _people as an ordinary kotlin map to use for some verifications use-cases.
val copyAsMap : StateFlow<MutableMap<Int, Person>> = people.map {
it.associateBy( { it.id }, { it } )
.toMutableMap()
}.stateIn(viewModelScope, SharingStarted.Eagerly, mutableMapOf())
however, with my attempt above, it (the copyAsMap) doesn't get updated when I try to modify the list (e.g delete) an item from the _people StateFlow
Any ideas..? Thanks!
Edit:
Nothing is collecting from the copyAsMap, I just display the values everytime an object is removed from _person state flow
delete function (triggered by an action somewhere)
private fun delete(personModel: Person) {
_person.update { list ->
list.toMutableStateList().apply {
removeIf { it.id == personModel.id }
}
}
copyAsMap.values.forEach {
Log.e("MapCopy", "$it")
}
}
So based on your comment how you delete the item, that's the problem:
_people.update { list ->
list.removeIf { it.id == person.id }
list
}
You get an instance of MutableList here, do the modification and you "update" the flow with the same instance. And, as StateFlow documentation says:
Values in state flow are conflated using Any.equals comparison in a similar way to distinctUntilChanged operator. It is used to conflate incoming updates to value in MutableStateFlow and to suppress emission of the values to collectors when new value is equal to the previously emitted one.
Which means that your updated list is actually never emitted, because it is equal to the previous value.
You have to do something like this:
_people.update { list ->
list.toMutableList().apply { removeIf { ... } }
}
Also, you should define your state as val _people: MutableStateFlow<List<T>> = .... This would prevent some mistakes you can make.

Dart: Maps nested in maps

I want to store various data for my app in a single place, in a map. In JS, I'd store in a JSON file, and I want to use the same sort of approach, but struggling with Dart. I can't seem to work with nested lists or maps.
Here's essentially what I want to do:
var items = {
"item1": {
"message" : "aa",
"nested1": {
"message": "bb",
"nested2" : {
"message" : "cc"
},
}
},
};
void main() {
var message1 = items["item1"]?["message"];
print(message1);
print(message1.runtimeType);
var message2 = items["item1"]?["nested1"]?["message"];
print(message2);
print(message2.runtimeType);
var message3 = items["item1"]?["nested1"]?["nested2"]?["message"];
print(message3);
print(message3.runtimeType);
}
I've been struggling to make this work in Dartpad.
message1 works as expected, but then I can't seem to work my way down the tree...
Is this a shortcoming with map literals? Do I need to use constructors? Or am I missing something bigger?
Your problem is that items is inferred to be of type Map<String, Map<String, Object>>, but Object does not have an operator []. Therefore when you eventually extract that Object, you will not be able to do anything with it until you cast it a more specific type.
What you probably want instead is to explicitly declare items as Map<String, dynamic> to disable static type-checking on the Map's values:
var items = <String, dynamic>{
"item1": ...
};
Of course, when you disable static type-checking, you are responsible for ensuring that the values you get from the Map are what you expect, or you will get NoSuchMethod or TypeError exceptions at runtime. If you do want static type-checking, you should use define custom classes instead of using a blob of key-value properties.

Remove Child From Firebase removes whole node swift

I have the following data structure:
"feed" : {
"756135 Washington" : {
"VbMvwmlNqGNUY44JmfPp" : {
"downvotes" : "downvotes",
"timestamp" : 1483396793247,
"upvotes" : {
"i5KHwJzhTTfA6FJ8Fb2qLHuLjHi2" : {
"timestamp" : 1483396826253
}
},
}
}
}
Now I want to remove the i5KHwJzhTTfA6FJ8Fb2qLHuLjHi2 node under upvotes but I still want the upvotes node to stay, just without any children. I'm using the following code, however this removes the whole node.
ref?.child("feed").child(city_localizer_string!).child(id!).child("upvotes").child(uid).removeValue()
Anything empty in firebase will always be removed automatically. Even if you try and create a new child with the value of nil it won't be added to your database.

Perform firebase query in a nested style. Best practice?

I am doing a practice app on an instagram like app on firebase and swift. The question I have is that I am finding myself nesting my firebase "observeSingleEventOfType" to obtain all the data I need such that I can put it in my "Post Class". I was wondering if there is a better way of doing it as it seems like it could take up alot of time just to load one post? (I am grabing one info, wait, then grab the next, wait, then grab the next,wait,grab the next... and put everything as one Post Item at the end of the chain)
Upon initial load, I need the location, top comments, whether or not the user liked the post, whether the user followed the post or not. Currently what I am doing is
->Create a geo query, grab the geo information. Inside the completion block, I have a observeSingleEventOfType to look for information from my posts node and store as dictionary. Inside the completion block of this, I create another observeSingleEventOfType call to get the top comments, then inside this completionblock, I create another observeSingleEventOfType to look for whether or not the user is following the post. Then inside this, I have all the data to store inside my Post class that looks like
init(postKey: String, distance: Double, topComments: [Comment], liked: Bool, followingPost: Bool, dictionary: Dictionary<String, AnyObject>) {}
Here is my Json structure.
{
"comments" : {
"postKEY123" : {
"CommentKEY123" : {
"comment" : "aa"
}
}
},
"follow" : {
"userId123" : {
"postKEY123" : true
}
},
"posts" : {
"postKEY123" : {
"commentCount" : 1,
"postDescription" : "Aa",
"likeCount" : 0,
"userId" : "userId123"
}
},
"users" : {
"userId123" : {
"email" : "user1#mail.com"
"liked" : {
"postKey123": true
}
},
}
"location" : {
"postKey123" : {
".priority" : "9q9hrjj7cd",
"g" : "9q9hrjj7cd",
"l" : [ 37.33769226, -122.02885785 ]
},
},
}
The reason that I have done it this way is so that the Json data is not nested. As an possible alternative method, would it be possible to fetch all the data for the post async in background and return it when all the info for that post is ready? I didnt think I could do that as you wouldnt be able to guarantee what and when the item comes back. This is why I grabbed the data one by one inside completion block of one another?
Thanks,

EXT JS 5: viewModel links variable id

I am using Ext JS 5.0.1 and I am trying to use links in the viewModel defined inside a view.
The example below works.
Ext.define("MyViewPackage.MyView", {
extend: "Ext.form.Panel",
alias: "widget.myview",
theIdToUse: 47,
viewModel: {
links: {
theProject: {
type 'mypackage.MyModelClassName'
id: 17 //This works. But not theIdToUse or this.theIdToUse.
//I would like to use a value provided from my view
}
}
}
});
I would like to use the value of 'theIdToUse' for the id property of 'theProject' defined in 'links'.
I have tried to simply put theIdToUse or this.theIdToUse but I always got the following error:
Cannot use bind config without a viewModel
Do you know how could I managed to use links with a variable id?
Thanks in advance!
Use linkTo, like:
Ext.define("MyViewPackage.MyView", {
extend: "Ext.form.Panel",
alias: "widget.myview",
theIdToUse: 47,
constructor: function(){
this.callParent(arguments);
this.linkTo('theProject',{
type 'mypackage.MyModelClassName',
id: this.theIdToUse
});
}
});
this.theIdToUse does not work because within the scope of the viewModel, this no longer refers to MyViewPackage.MyView, but to the viewModel itself.
Even if you could get a reference back to MyViewPackage.MyView, say using ComponentQuery, the component does not yet exist at the point that the viewModel is being initialized, so you will get an error Cannot read property 'theIdToUse' of undefined.
You would probably be better off using some sort of two way binding between the view and viewModel, but I would need to know more about what you're trying to achieve to say exactly how.
Previous answer were pretty correct, except that in your case this would refer to window, not viewModel. This is due to in Ext.define you are passing anonymous object without some scope, so window scope would be used by default.
Suppose you should use something like this:
Ext.define("MyViewPackage.MyView", {
extend: "Ext.form.Panel",
alias: "widget.myview",
bind: {theIdToUse: "{id}"}
viewModel: {
links: {
theProject: {
type 'mypackage.MyModelClassName'
id: 17 //This works. But not theIdToUse or this.theIdToUse.
//I would like to use a value provided from my view
}
}
}
});
Although the question is from long time ago, I leave a possible solution for further viewers.
Try:
Ext.define("MyViewPackage.MyView", {
extend: "Ext.form.Panel",
alias: "widget.myview",
config: {
theIdToUse: 47,
},
viewModel: {
links: {
theProject: {
type 'mypackage.MyModelClassName'
id: null // Will be copied from config in initConfig
}
}
},
initConfig: function (config) {
this.config.viewModel.links.theProject.id = config.theIdToUse ;
this.callParent([config]) ;
}
});
You will be able to instanciate your panel with different ids:
items: [
{
xtype: 'myview',
theIdToUse: 47
},{
xtype: 'myview',
theIdToUse: 32
}
],
Even with:
Ext.create('MyViewPackage.MyView', {theIdToUse: 12}) ;

Resources