Dynamically created layer names, problems with eval() - eval

I want to create some layers with names taken from database. "Trees" in database becomes a "Layer_Trees" openlayers layer.
I tried many things with eval function, yet with no success. Seems like its completely uncapable of defining new variables.
function addLayer_ImageWMS(SourceName,SourceLayerName) {
LayerName="Layer_" + SourceLayerName;
eval(LayerName) = new ol.layer.Image({
title: LayerName,
source: new ol.source.ImageWMS({
url: SourceName,
params: {
'LAYERS': SourceLayerName,
'TRANSPARENT': 'true'
}
})
})
LayersArray.push(LayerName);
}
If I remove "eval()" everything is working, but layers are inaccessible from outside.
Openlayers 3. I have to adress this layers from outside of this function, because they are turned on and off through a menu.
Is there any simple way to do this?
I was planning to turn them on and off with such code:
SourceName = "Layer_" + $(layer).children("#SourceName").val();
IsChecked = $(layer).children(".Style_LayerList_Radiobutton").prop("checked");
eval(SourceName).setVisible(IsChecked);

You don't need eval for this. Simply use an object like this:
var layers = {};
layers['Layer_' + SourceLayerName] = new ...;
Later you can access the layer with:
layers['Layer_Trees'].setVisible(true);

Related

google-realtime-api - how to access all the objects in a file

So I am trying to add multiple objects to my google-realtime-api app. For example, I've got something like this:
function onFileInitialize (model) {
var collaborativeList = model.createList();
collaborativeList.pushAll(['Cat', 'Dog', 'Sheep']);
model.getRoot().set('demo_list', collaborativeList);
var collaborativeList2 = model.createList();
collaborativeList2.pushAll(['1', '2', '3']);
model.getRoot().set('demo_list2', collaborativeList2);
My question is how can I access them all at the same time? So it would be possible to render them and add event-listeners to them without having to do it separately by first getting 'demo_list' and then 'demo_list2' and repeating a lot of code.
Is it possible with realtime to do something like:
for (var i=0...) { doc.getModel().getRoot().get(i); };
?
The root is a CollaborativeMap, so you can use getKeys or getValues to iterate through all the items.

How do I delete objects within objects in Angular-Meteor?

NOTE: the following code and demo are extracted from a larger Meteor + Angular project.
I have the following functions to select and delete objects:
DEMO: http://plnkr.co/edit/Qi8nIPEd2aeXOzmVR6By?p=preview
$scope.selectParty = function(party) {
$scope.party = party;
$scope.type = party.type;
$scope.date = party.date;
}
$scope.deletParty = function(party) {
$scope.parties.remove(party);
}
$scope.selectOrganizer = function(organizer) {
$scope.organizer = organizer;
$scope.name = organizer.name;
$scope.title = organizer.title;
}
$scope.deletOrganizer = function(organizer) {
$scope.party.organizers.remove(organizer);
}
The Select action works on both Parties and Organizers as you can see in the demo, displaying the data in the table underneath.
The Delete action doesn't work. Although, let me point out that in my app, the one I have on my machine and currently working on in Meteor, the Delete action works splendidly on Parties, meaning the syntax "$scope.parties.remove(party)" works. But it doesn't work on the plnkr demo for some reason :(
My question is really about the Organizers Delete action, where I'm targeting an object (organizer) inside an array inside the selected object (party)… that one doesn't work. I'm wondering why, and what is the right syntax.
NOTE 2: I'm aware of Angular's splice and index but I can't use them here as I'm not simply working with Angular arrays but with database data in Meteor.
Thanks!
The organizer is a part of the party object and not a collection on it's own. So what you would need to do is remove the party from the object and then save the party object.
Note2 is incorrect. Unless you wrote your question and plunker wrong.

angular.js using highcharts-ng not maintaining series order, unless I force $apply (which throws already in progress error)

This may be unfixable, but I was hoping someone may have come across this before and found a workaround.
Highcharts-ng seems to merge series data with existing data in such a way that I cannot maintain the ordering of series. I specifically want to show two series, call them A & B, from left to right (because the form controls are organized that way).
So, I'm starting with a series A, then I add a B, then change A, and it's now in the order B & A.
I've looked at the highcharts-ng code, and I can understand why it's happening (see processSeries method below).
The only workaround that I've been able to get to work is to completely reset the series data and call $apply, which of course you cannot do in the middle of another apply.
$scope.chartConfig.series.length = 0
$scope.chartConfig.xAxis.categories.length = 0
$scope.$apply(); # force update with empty series (throws $apply already in progress error)
I'd really like to know if there's an option that I can set, or some other workaround that would allow me to use this how I'd like without having to resort to editing the directive.
var processSeries = function(chart, series) {
var ids = []
if(series) {
ensureIds(series);
//Find series to add or update
series.forEach(function (s) {
ids.push(s.id)
var chartSeries = chart.get(s.id);
if (chartSeries) {
chartSeries.update(angular.copy(s), false);
} else {
chart.addSeries(angular.copy(s), false)
}
});
}
Thanks a bunch!
Answering my own question. It seems the workaround is to have placeholders for the series in fixed positions, and do updates rather than replacements, such as:
$scope.chartConfig.series[0].data = [1,2,3]
$scope.chartConfig.series[0].name = 'foo'
$scope.chartConfig.series[1].data = [4,5,6]
$scope.chartConfig.series[1].name = 'bar'
Even doing something like:
$scope.chartConfig.series[0] = {name: 'foo', data: [1,2,3]}
$scope.chartConfig.series[1] = {name: 'bar', data: [4,5,6]}
results in the ordering issue described above.

Overwrite properties in angular forEach

I imagine this is an easy thing to do, but I wasnt able to find the information I was looking for through google. I have popupProperties which is just default stuff. I then call to the service which returns specific overrides depending on the popup. How can I iterate through all of the service's overrides and apply them to the popupProperties?
var popupProperties = getDefaultPopupProperties();
var popupOverrides= popupService.getPopupOverrides(currPopupId);
angular.forEach(popupOverrides, function(popupProperty, propertyName){
//replace defaults with popupData's properties
});
You should have a look at the solution of Josh David Miller which uses the extend method of angular (documentation).
var defaults = {name:'John',age:17,weight:55};
var overrides = {name:'Jack',age:28,color:'brown'};
var props = angular.extend(defaults, overrides);
// result
props: {
name:'Jack',
age:28,
weight:55,
color:'brown'
}
The values are copied in the defaults variable. There is no need of using the return value (var props =).
I presume you mean both functions are returning objects with a number of properties (as opposed to an array).
If so, the following should work - just JavaScript, nothing AngularJS specific:
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
See this question for more details How can I merge properties of two JavaScript objects dynamically?

Parameterizing the name of the store in backbone-localStorage.js

The standard way to use the localStorage plugin for Backbone.js works like this:
App.WordList = Backbone.Collection.extend({
initialize : function(models, options){
},
localStorage : new Store('English')
}
But I want to make different, parallel wordlist collections in different languages. So, I want to be able to instantiate the name of the Store upon initialization of the collection. AFAICT, this works ok:
App.WordList = Backbone.Collection.extend({
initialize : function(models, options){
this.localStorage = new Store(options.language);
}
}
Then I can instantiate a WordList like:
english = new Wordlist([], {language: 'English'});
Or:
chinese = new Wordlist([], {language: 'Chinese'});
The thing is, I haven't really seen this done in any other examples and I'm wondering if anyone out there would have any "Eek! Don't do that, because..." sorts of reactions.
EDIT
I should add that I have already tried doing it this way:
App.WordList = Backbone.Collection.extend({
initialize : function(models, options){
},
localStorage : new Store(options.store)
}
And then:
chinese = new Wordlist([], {language: 'Chinese'});
But for some reason options.store is coming up undefined.
It's easier to explain myself as an answer, so I'll go ahead and give one.
In:
App.WordList = Backbone.Collection.extend({
initialize : function(models, options){
....
},
localStorage : new Store(options.store)
})
This is really little different from
var newInstanceConfig = {
initialize : function(models, options){
....
},
localStorage : new Store(options.store)
}
App.WordList = Backbone.Collection.extend(newInstanceConfig);
Think of it this way; there's nothing magical about the object being passed in to Backbone.Collection.extend(...). You're just passing in an ordinary object. The magic happens when Backbone.Collection.extend is invoked with that object as a parameter
Thus, the options parameter of the object method initialize is completely different that which is being passed in to new Store(...). The function being assigned initialize is defining the scope of options. Who knows where the one referred to in new Store(options.store) is defined. It could be window.options or it could be options defined in some other scope. If it's undefined, you're likely getting an error
That being said, I only see two or three strategic options (oh jeez, forgive the pun please!).
Whenever you're creating a new instance of the collection, either:
Pass in the language and let your Backbone collection create the new Store(..) where needed.
Pre-Create the Stores and either pass or give the specific Store want to that instance (either directly through its constructor or maybe you have your constructor "look-up" the appropriate pre-created Store).
And finally, I guess you could delegate the task of creating stores to another object and have it implement either options one or two. (Basically a Store Factory/Resource Manager kinda thing).
What you need to figure out is which one of those strategies should work for you. I have never used localStorage so, unfortunately, I can't help you in that regard. What I can do is ask, is there ever going to be multiple instances created from App.Wordlist where there might accidentally be created two of the same kind of Store?
In fact, I've got another question. where is this Store defined? Are you sure that's not defined somewhere in one of your other API libraries you're using? Perusing the localStorage docs I know about mentions something of a Storage constructor but nothing of a Store. So you might want to figure out that as well.
Edit #1: Nevermind, I see you mentioned where Store was defined.
I got around this by creating a method which allows you to configure the localStorage after instantiation:
var PageAssetCollection = Backbone.Collection.extend ({
initialize: <stuff>
model: <something>
...
setLocalStorage: function ( storageKey ) {
this.localStorage = new Backbone.LocalStorage(storageKey),
},
});
you can then set the localStorage after you have set up the collection:
fooPageAssets = new PageAssetCollection();
fooPageAssets.setLocalStorage('bar');

Resources