I have 2 models in my application that I bind to sap.ui.core.
The following code is from my main view. Which is a split-app.
var checks = {
items: [
{
checklist: "ContainerCheck",
title:"Scan RFID container",
}
// etc...
]}
;
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData(checks);
sap.ui.getCore().setModel(oModel, "checks");
In another view I want to bind data to the masterpage
var oItemTemplate = new sap.m.ActionListItem({
title : "{title}",
icon : "sap-icon://activity-2",
activeIcon: "sap-icon://activity-2",
type : sap.m.ListType.Active,
});
this.oList = new sap.m.List({
itemPress: [oController.onListSelect, oController]
});
this.oList.bindItems("checks>/items",oItemTemplate);
However I'm not seeing any data in the list. I'm quite sure the sPath is correct checks>/items. Is it not possible to use this sPath because the model is bind to sap.ui.core. Or am I missing something else?
I'm pretty sure you have to prefix the propertyBinding with the models name:
var oItemTemplate = new sap.m.ActionListItem({
title : "{checks>title}",
...
});
This should work.
Try this this.oList.bindItems("{checks>/items}", oItemTemplete); instead of this.oList.bindItems("checks>/items",oItemTemplate);
I stumbled about the same problem and after a while I found this comment:
A control can only bind to one model, so if you have a container control with an assigned model, all controls contained in this container can only see the local model of the container and are no longer able to bind to the global model.
I assume that is the problem in your code. At least that's the one in mine :-)
Related
I have created a datatable showing a list of persons and their details. When the datatable is clicked, it has to show the entity of the single person with their details but my problem is, when I click the datatable it is opening a chat box showing the entity of the last clicked person changing all other chat box details.
1.How can I limit the append directive, that is, one chatbox for one id?
2.How to display the name of the particular person without changing the older chat box entity?
Here is the link to Plunker http://plnkr.co/edit/VTWcZQjlAda0KQ9sjFzI?p=preview
Actually i really think there is no need for a directive here.
It can simply be done by using ng-repeat and a collection.
See it working in this plunker
I added this in the controller :
$scope.bottomListCollection = [];
$scope.addToBottomList = function(artist) {
$scope.bottomListCollection.push(artist);
}
And this kind of ng-click on your rows :
ng-click="addToBottomList(item)"
Some advices to do things cleaner in angular :
Never use :
$compile.
$element.
$broadcast.
Jquery.
Take care of custom directives, theses are 90% miss-used.
Just a reminder : Directives are intended to add a behavior on an element. Not adding html.
Hope it helped.
Some tips that fix your issue
childScope = $scope.$new(true);
to ve an isolated scope you ve to use the first parameter of $new method
for more info look at the docs ($new(isolate, parent); --> https://docs.angularjs.org/api/ng/type/$rootScope.Scope)
then you need to add a control on the AppendText function like this to check if the same chat already exist
$scope.AppendText = function(idx) {
$scope.userInfo = $scope.artists[idx];
var chat = $('#chat_'+$scope.userInfo.shortname);
console.log(chat);
if ($scope.stage === 'Add' && chat.length==0 ) {
childScope = $scope.$new(true);
childScope.userInfo = $scope.userInfo; //<--- add old scope info to new scope
var compiledDirective = $compile('<div my-directive></div>');
var directiveElement = compiledDirective(childScope);
$('.my-directive-placeholder').append(directiveElement);
} else {
$scope.stage = 'Add';
}
}
working plunker http://plnkr.co/edit/TFjlN0U2i4irKtG2D5yu?p=preview
To answer the second part of your question : Create an isolate scope!
That can be done by passing true while creating a new scope: childScope = $scope.$new(true).
Once the isolate scope is created, you can do:
childScope.userInfo = $scope.userInfo;
PLUNK : http://plnkr.co/edit/IxPh4EmLpr8WAqRWtRlo?p=preview
Also, a hackish solution using one time databinding (not recommended):
http://plnkr.co/edit/RjZNOSyaemqg2eZ4Gma1?p=preview
To answer the first part: You could keep track of the id's that are passed to the $scope.AppendText function perhaps?
PLUNK: http://plnkr.co/edit/BCNju0rToyVYvNjqzVON?p=preview
Hope this helps! IMHO it would be much more simpler if you could just ng-repeat over your json data to generate the chatboxes.
In my Backbone.js application I have a collection of models.
These models can be 'active' or not. When one model becomes active I want to ensure every other model in the collection is or becomes not active.
Currently I am achieving this by caching the currently active model, listening for change events and determining whether I should set the cached model to not active.
This works, BUT, it doesn't scale well. Not as I start adding more and more properties that should only be positive on one model per collection I finding duplicated the code is messy.
Any suggestions guys?
Here is my code
EOT.Collection.VehiclesBase = Backbone.Collection.extend({
model : EOT.Model.Vehicle,
currentOpen : false,
initialize : function(){
this.on('change:open', this.ensureSingleOpen);
},
ensureSingleOpen : function(changed){
//ensure the last open vehicle closes
if(changed!=this.currentOpen) {
if(this.currentOpen){
this.currentOpen.set('open',false);
}
if(changed.get('open')){
this.currentOpen = changed;
this.trigger('change:currentOpen');
}
}
}
});
I think you can do what you want pretty cleanly using the built in each function:
EOT.Collection.VehiclesBase = Backbone.Collection.extend({
model : EOT.Model.Vehicle,
initialize : function(){
this.on('change:open', this.ensureSingleOpen);
},
ensureSingleOpen : function(changed){
this.each(function(m) {
m.set({open: m === changed}, {silent: true});
});
}
});
Seems that #net.uk.sweet answer has a minor syntax issue - i.e. this.each should probably be invoked instead of being set.
EOT.Collection.VehiclesBase = Backbone.Collection.extend({
model : EOT.Model.Vehicle,
initialize : function(){
this.on('change:open', this.ensureSingleOpen);
},
ensureSingleOpen : function(changed){
this.each(function(m) {
m.set({open: m === changed}, {silent: true});
});
}
});
Check out Backbone Picky!
It's a really lightweight Backbone library that is easy to use. It sounds great for what you are looking to do.
Specifically, you would want to use Picky.SingleSelect (taken from the github docs):
Picky.SingleSelect:
Creates single-select capabilities for a Backbone.Collection, allowing a single model to be exclusively selected within the colllection. Selecting another model will cause the first one to be deselected.
I'm trying to pick up backbone and would like to do a simple image gallery app but am having problems.
I'd like to instantiate my view with a collection of items (named itemsArray) and then load the first model of that collection into a view. This view will provide a previous and next button and I've set up the events.
I'm confused about how to pass this collection into a Backbone view and tell it to load the first element. Also, manipulating the collection with prev / next doesn't seem to be working correctly. I asked this question before (backbone - trying to rerender a view with the next or previous model in a collection) but think it's better if I post the whole fragment here. I have seen sample code similar to this in tutorials but I think the loading of the single model with knowledge of the collection has proven problematic. I have provided the full source code below:
<div id='item-container'></div>
<script type='text/template' id='tmp'>
<%=header %>
<img src='<%=assets[0].url %>' />
<div class='next-btn'>next</div> <div class='prev-btn'>prev</div>
</script>
<script>
$(document).ready(function(){
var arc={};
// 2. items to be made into an Items collection
var itemsArray=[{'id':4, 'header':'my header','detail':'my detail', 'price':'$12.25', assets:[{'url':'/tmp-images/surf.jpg'}]},
{'id':7, 'header':'my header 2','detail':'my detail 2', 'price':'$14.25', assets:[{'url':'/tmp-images/jamaica.jpg'}]},
{'id':11, 'header':'my header 3','detail':'my detail 3', 'price':'$21.00',assets:[{'url':'/tmp-images/jamaica-2.jpg'}]}
];
// 3. item class
arc.Item = Backbone.Model.extend({});
// 4. items collection made up of item
arc.Items = Backbone.Collection.extend({
model:arc.Item
});
var items = new arc.Items(itemsArray);
//console.log(menu_items);
arc.ItemsGalleryView = Backbone.View.extend({
el: $('#item-container'),
events: {'click .next-btn' : 'loadNext', 'click .prev-btn':'loadPrevious' },
template:_.template($('#tmp').text()),
initialize: function() {
_.bindAll( this, 'render' );
// 5. this is definitely wrong, trying to render template with single instance of model
// seems like I should be doing something like this.collection.at(0) or something but that isn't working
//this.render(this.model);
/* 6. works but not an array
this.render({header:'my name',assets:[
{url:'/image/some.jpg'}
]});
*/
// 7. not working header is not defined
this.render(this.collection.at(0)); // error 'header is not defined'
console.log(this.collection.at(0)); // in console this kinda looks like a model but do I need to call another method on it?
},
render: function(xModel) {
var compiled=this.template(xModel);
this.$el.html(compiled);
return this;
},
loadNext: function(){
// 8. not sure what to do here
},
loadPrevious: function(){
console.log('i want to load Previous');
// 9. not working
this.render(this.collection.prev());
}
});
var itemView=new arc.ItemsGalleryView({ collection: items });
});
</script>
Any help is greatly appreciated. How would I pass a collection? and then manipulate where I am in the collection via events?
thx
When passing a model to a template, note that every attribute is held in a special hash. For you, it'd be model.attributes.header. (so <%= attributes.header %>)
It is usually suggested you pass your model attributes directly to your templates though: this.render(this.collection.at(0).toJSON()); (and that'll work with your current template)
As already mentioned, you usually do not pass arguments to render(). You're also not actually appending your #tmpl template to your #item-container.
I have created a working jsfiddle with your code. I've demonstrated creating a separate view for your collection and model, as I feel this was confusing things.
I am working with Dojo, and I have a small requirement. I am using a store to create a Memory. I have a hardcoded list so that I can set this list to a Dojo data grid store and thereby perform some rowclick functions. My issue is that I am not able to set the store, and I am getting an error,
this.headerContentNode.firstChild is null. Please can anybody help me out?
the code snippet....
postCreate : function () {
//publist, sublist etc
this._handleLogDetails();
},
//methods...
_handleLogDetails : function(){
alert("hello...h..");
var theGreatestTeamOfAllTime = [ {
"jobName":"12",
"jobId":"Jim Kelly",
"status":"QB",
"timeStamp":"0"
},
{
"jobName":"1",
"jobId":" Kelly",
"status":"B",
"timeStamp":"10"
}
];
var clientJobStore = this.jobModel.getLogStore();
clientJobStore.setData(theGreatestTeamOfAllTime);
var thisData = new ObjectStore({objectStore: clientJobStore});
this.dapJobStatusGrid1.setStore(thisData); // attach point of dojo data grid, getting an error at this point...
Hard to say exactly what the issue is here without seeing how the grid is configured, but this is likely caused by one of the following:
You didn't call startup() on your grid.
When constructing your grid, you did not provide a DOM node for the grid.
For example, perhaps try something like the following, where the second argument is the DOM node the grid should be attached to.
var options = {// some options};
var foo = new DataGrid(options, someContainer.domNode);
foo.startup();
I have an ExtJS grid like so:
var grid = new Ext.grid.GridPanel({
...
});
I'd like to be able to re-use this grid so that I can have it multiple instances of it that all act independently. Is the only way to do this is by using Ext.extend, or is there another way? I don't really need to extend it, I just need to be able to create multiple instances of it.
If you really just need two grid instances, then create another one as Upper Stage said.
If you need to share a config among multiple grids, you could save the config as a separate JS object that you then pass into the grid constructor each time you create one.
var myCfg = { ... };
var grid1 = new Ext.GridPanel(Ext.apply(myCfg, { /* other options */ }));
var grid2 = new Ext.GridPanel(Ext.apply(myCfg, { /* other options */ }));
If you are going to reuse the grid with a particular configuration across your app or in multiple apps, then a subclass may be the best way to go.
This tutorial reviews several different methods for reusing functionality and would be a good starting point for you to decide what approach best suits your needs (if you need something beyond two basic instances).
Ext.Component#cloneConfig() perhaps?
Can you simply instantiate new objects?
var anotherGrid = new Ext.grid.GridPanel({
...
});
Ext has decent support for subclassing. This means you can extend the standard grid and instantiate that:
Foo = {};
Foo.BarGrid = function(config) {
Foo.BarGrid.superclass.constructor.call(this, config); //call the default grid constructor
}
Ext.extend(Foo.BarGrid, Ext.grid.GridPanel, {
//grid config
});
var grid = new Foo.BarGrid({/*minimal config*/});
You can even register your own xtype and use that instead of newing it:
Ext.reg('foobargrid', Foo.BarGrid);
var pane = new Ext.TabPanel({
items: [{xtype: 'foobargrid'}]
});
EDIT Misread the question. Since you obviously know about Ext.extend sharing the config, as suggested by bmoeskau, might just do the trick for you.