Referencing binding annotations dynamically in Polymer 1 - polymer

I'm trying to set up a function in Polymer 1.0 which will allow a JSON response to tell my application which {{BindingVariable}} in which to insert the response. Unfortunately, the syntax for referencing these binding variables seems to be similar to this:this.BindingVariable, which doesn't allow for dynamic variable names.
What I really need is a way to reference these dynamically like how we can reference anything else in the DOM/PolyDOM. For example: document.querySelector('#'+elementID).
Is there any way to reference binding annotations dynamically? I've searched through the entire Polymer DOM and can't find them listed anywhere even though I know they're in the page.
example
app._onResponseRetrieved = function(e) {
for (var key in e.detail.response) {
// none of these work, but they demonstrate what I'm trying to accomplish
// this.key = e.detail.response[key];
// this.querySelector(key) = e.detail.response[key];
// window[key] = e.detail.response[key];
// document[key] = e.detail.response[key];
// Polymer.dom(key) = e.detail.response[key];
}
JSON Sent to _onResponseRetrieved
{"contactFormOutput":"Success!"}
Binding Annotation in index.html
<div>{{contactFormOutput}}</div>

this[key] = e.detail.response[key];
Javascript allows [] on any object for dynamic property referencing

Related

How can I remove or hide an object on the model tree panel in Forge Viewer?

I need to hide (make it go away completely) from the model tree panel in Viewer.
I already tried overriding methods from the Viewer (some other stuff is done that way), but the Tree-related methods and objects are not accessible for extending. It also seems too dangerous to mess with instanceTree data, like removing the dbId from the nodes list.
I'm running on the latest Viewer code (6.5.3), and writing pure javascript extensions.
For example, I tried overriding this function, which is used internally to determine if a node should or not be displayed. It doesn't work, neither does overriding the same function on the ModelStructureTreeDelegate:
Autodesk.Viewing.UI.TreeDelegate.prototype.shouldCreateTreeNode = function (dbId)
{
// original code on the viewer.js is:
// return true;
let itGo = true;
// _objectsHiddenInTree is populated with dbIds of objects to be hidden right after initializing the viewer
_objectsHiddenInTree.forEach(x => {
if (x == dbId){
itGo = false;
}
});
// return false; doesn't work either
return itGo;
};
Is there a way to do this from the Viewer side? I mean, to remove an item from the model tree?
If it's more viable, removing the object from the scene altogether is also a valid option. But I can't remove it from the model before sending to model derivative, it has to be done when opening the Viewer, or before opening the Tree Model panel.
Personally the easiest way would be to access node element via viewer.modelstructure and use styling to hide the node:
<style>
.yourHiddenNodeClass{display:none!important}
</style>
...
<script>
let modelStructureControl = viewer.modelstructure;
modelStructureControl.createUI(); //initialize the panel if it hasn't
let treeViewControl = modelStructureControl.tree;
let modelDelegate = treeViewControl.getDelegate(model.id);
treeViewControl.addClass(modelDelegate, dbid, "yourHiddenNodeClass", false) //hide a node - last boolean to toggle recursiveness
...
treeViewControl.removeClass(modelDeleagate, dbid, "yourHiddenNodeClass", false) //remove your custom class
</script>
And to hide a node completely:
model.visibilityManager.setNodeOff(dbid, true) // true=hide, false=show
Bryan's answer gave me an idea that seems to work for now:
Every element on the tree panel has an atribute 'lmv-nodeid', with the dbId of the object. So I looked for it, and added the 'hidden' attribute to the div:
document.querySelectorAll('[lmv-nodeid="' + objectDbId + '"]')[0].hidden = true;
His answer is still better, though, because there is no guarantee that the attribute will remain on newer versions of the Viewer, whereas the Viewer classes and methods are more stable and future-proof.

How to handle $ctrl. in AngularJS?

I have a Methode from an API. It returns a promise which resolves to an $ctrl(?) object. This objects should contain a measurement and will be updated whenever it receive a new data.
getMeasurements.latest(filter) //only a object to filter through all measurements
.then(function (latestMeasurement) {
$ctrl.latestMeasurement = latestMeasurement;
});
My problem is that I don't know how to work with this data or display it in my html file. How does $ctrl work?
Here the documentation of the API
$ctrl is the view model object in your controller. This $ctrl is a name you choose (vm is another most common name), if you check your code you can see the definition as $ctrl = this;, so basically its the this keyword of the controller function.
So now if you are using $ctrl.latestMeasurement = 'someValue', then its like you are adding a property latestMeasurement to controller function.
Now how to use it in HTML?
To access the latestMeasurement property in HTML your code must have <h1>{{$ctrl.latestMeasurement}}</h1> (H1 tag is just an example.)
Here $ctrl is different from what I explained above on controller part. Here $ctrl is the value used for controllerAs property of the controller. But $ctrl is the default value of the controllerAs property, so your code may not have the controllerAs property defined, so Angular will take default value $ctrl in HTML.
This is where most people gets confused. So let me explain,
Assume in your new controller you have declared your this keyword to variable vm, and you set your controllerAs property to myCtrl, i.e;
controllerAs: 'myCtrl' while defining controller properties.
var vm = this; in your controller function.
In this case in js you have to use vm for setting values, and in HTML you have to use myCtrl. For example,
in JS controller function vm.test = 'Hello world';
in HTML <span ng-bind="myCtrl.test"></span>
The result Hello world will be displayed in your page.
Why $ctrl and not $scope?
The view model object model concept is introduced in AngularJS 1.5, it is actually part of migrating to Angular 2 where $scope no longer exsist. So in 1.5 they introduced new approch but did not removed $scope completely.
Hope the answer helped.
For basic Javascript concepts you can see http://javascriptissexy.com/16-javascript-concepts-you-must-know-well/
For more detailed AngularJS $ctrl concept you can see https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/
I suppose you are toking about this.
In this case, the
$ctrl.latestMeasurement
can means:
$ctrl, the controller where you are running this code. You can change it by $scope for example, and get the same result.
latestMeasurement, the variable where you want to store the last value of the measurement.
To explain my point of view let see the code below
<div ng-app="MeasurementApp">
<div ng-controller="MeasurementController">
<h1>{{latestMeasurement2}}</h1>
</div>
</div>
There you can see a simple angularjs app that shows a variable called latestMeasurement2 in a div and its controller called MeasurementController. Then, to display the value let check your code.
angular.module('MeasurementApp', [])
// creating the controller
.controller('MeasurementController', function(c8yMeasurements, $scope) {
// creating the variable and let it empty by now.
$scope.latestMeasurement2 = "";
// Your code
var filter = {
device: 10300,
fragment: 'c8y_Temperature',
series: 'T'
};
var realtime = true;
c8yMeasurements.latest(filter, realtime)
.then(function (latestMeasurement) {
// The latestMeasurement is where the measurement comes
// Here we just assign it into our $scope.latestMeasurement2
$scope.latestMeasurement2 = latestMeasurement;
});
});
As the documentation says
// $scope.latestMeasurement2 will be updated as soon as a new measurement is received.
$scope.latestMeasurement2 = latestMeasurement;
Hope this helps!

Error with custom Search and Replace function for Google Sites

I'm trying to use a script to replace a particular string with a different string. I think the code is right, but I keep getting the error "Object does not allow properties to be added or changed."
Does anyone know what could be going wrong?
function searchAndReplace() {
var teams = SitesApp.getPageByUrl("https://sites.google.com/a/directory/teams");
var list = teams.getChildren();
list.forEach(function(element){
page = element.getChildren();
});
page.forEach(function(element) {
var html = element.getHtmlContent();
html.replace(/foo/, 'bar');
element.setHtmlContent = html;
});
};
Try This:
Javascript reference:
The replace() method returns a new string with some or all matches of a pattern replaced by a replacement.
I think the issue here is that forEach cannot change the array that it is called upon. From developer.mozilla.org "forEach() does not mutate the array on which it is called (although callback, if invoked, may do so)."
Try doing it with a regular loop.

Special JSON binding in WinJS ListView

I have problems binding this JSON to my list view.
http://pubapi.cryptsy.com/api.php?method=marketdatav2
No data is displayed.
Data.js
(function () {
"use strict";
var _list;
WinJS.xhr({ url: 'http://pubapi.cryptsy.com/api.php?method=marketdatav2' }).then(
function (response) {
var json = JSON.parse(response.responseText);
_list = new WinJS.Binding.List(json.return.markets);
},
function (error) {
//handle error
}
);
var publicMembers =
{
itemList: _list
};
WinJS.Namespace.define("DataExample", publicMembers);
})();
HTML:
<section aria-label="Main content" role="main">
<div id="listItemTemplate" data-win-control="WinJS.Binding.Template">
<div class="listItem">
<div class="listItemTemplate-Detail">
<h4 data-win-bind="innerText: label"></h4>
</div>
</div>
</div>
<div id="listView" data-win-control="WinJS.UI.ListView" data-win-options="{itemDataSource : DataExample.itemList, itemTemplate: select('#listItemTemplate'), layout: {type: WinJS.UI.GridLayout}}"></div>
</section>
I feel that the API is not that well formed.
Isnt this part a bit odd?
"markets":{"ADT/XPM":{...}...}
There are three things going on in your code here.
First, a ListView must be bound to a WinJS.Binding.List's dataSource property, not the List directly. So in your HTML you can use itemDataSource: DataExample.itemList.dataSource, or you can make your DataExample.itemList dereference the dataSource at that level.
Second, you're also running into the issue that the declarative binding of itemDataSource in data-win-options is happening well before DataExample.itemList is even populated. At the point that the ListView gets instantiated, _list and therefore itemList will be undefined. This causes a problem with trying to dereference .dataSource.
The way around this is to make sure that DataExample.itemList is initialized with at least an empty instance of WinJS.Binding.List on startup. So putting this and the first bit together, we have this:
var _list = new WinJS.Binding.List();
var publicMembers =
{
itemList: _list.dataSource
};
With this, you can later replace _list with a different List instance, and the ListView will refresh itself.
This brings us to the third issue, populating the List with your HTTP response data. The WinJS.Binding.List takes an array in its constructor, not an object. You're passing the parsed JSON object straight from the HTTP request, which won't work.
Now if you have a WinJS.Binding.List instance already in _list as before, then you can just walk the object and add items directly to the List as follows:
var jm = json.return.markets;
for (var i in jm) {
_list.push(jm[i]);
}
Alternately, you could populate a separate array and then create a new List from that. In this case, however, you'll need to assign that new List.dataSource to the ListView in code:
var jm = json.return.markets;
var markets = [];
for (var i in jm) {
markets.push(jm[i]);
}
_list = new WinJS.Binding.List(markets);
var listview = document.getElementById("listView").winControl;
listview.itemDataSource = _list.dataSource;
Both ways will work (I tested them). Although the first solution is simpler and shorter, you'll need to make sure to clear out the List if you make another HTTP request and repopulate from that. With the second solution you just create a new List with each request and hand that to the ListView, which might work better depending on your particular needs.
Note also that in the second solution you can remove the itemDataSource option from the HTML altogether, and also eliminate the DataExample namespace and its variables because you'll assign the data source in code each time. Then you can also keep _list entirely local to the HTTP request.
Hope that helps. If you want to know more about ListView intricacies, see Chapter 7 of my free ebook from MSPress, Programming Windows Store Apps with HTML, CSS, and JavaScript, Second Edition.

CodeMirror textarea.getAttribute is not a function error in mvc3 application

I'm using CodeMirror in my ASP.NET MVC 3 application,
CodeMirror's version is up to date(2.34)
my textarea looks like this:
#Html.TextAreaFieldFor(s => s.Data.CodeBehind, htmlAttributes: new Dictionary<string, object> { { "class", "textbox codeBehind nffp-code" } })
I use CodeMirror like this:
var a = CodeMirror.fromTextArea($code, {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-csharp"
});
where $code is
var $code = jQuery('.nffp-code', $root);
And after page load I have this error:
TypeError: textarea.getAttribute is not a function
codemirror.js
Line 2209
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
I used this manual for using CodeMirror:
manual
Even thought, I'm a total noob in JS, I guess it's hard to do it wrong, still I did.
Any Ideas how to fix the problem?
You need to use document.getElementById() instead of the jQuery lookup.
document.getElementById('contents'); //returns a HTML DOM Object
var contents = $('#contents'); //returns a jQuery Object
In jQuery, to get the same result as document.getElementById(), you can access the jQuery Object and get the first element in the object (Remember JavaScript objects act similar to associative arrays).
var contents = $('#contents')[0]; //returns a HTML DOM Object