Access selectedItems of an <iron-list> on change - polymer-1.0

Having trouble understanding how to access the selectedItems property of an iron-list. When bound to a property of the parent, I can output it's contents using a template, but an observer or computed binding does not fire when it changes and I can't seem to output it's contents.
If anyone could point out what I'm doing wrong, how I can read the selectedItems for logic, or how I can observe changes to an iron-list selectedItems property, I would greatly appreciate the know how. Thanks.
Below is some example code to show how I am using the selectedItems property of iron-list:
<dom-module id="example-component">
<template>
<iron-list
id="dataList"
items="[[data]]"
as="item"
multi-selection
selection-enabled
selected-items="{{selectedItems}}">
<template>
<span>[[item.data]]</span>
</template>
</iron-list>
<template is="dom-repeat" items="[[selectedItems]]" index-as="index">
<div>[[item.data]]</div> <!-- this displays any selected item -->
</template>
</template>
<script>
Polymer({
is: 'example-component',
properties: {
data: {
type: Array,
value: [
{
'data': "item 0"
},
{
'data': "item 1"
}
]
},
selectedItems:
{
type: Object,
observer: '_selectedItemsChanged'
}
},
_selectedItemsChanged: function(){
console.log(this.selectedItems); //this neither runs nor outputs anything when an item is selected
}
});
</script>

From the docs:
Finally, to observe mutations to arrays (changes resulting from calls to push, pop, shift, unshift, and splice, generally referred to as “splices”), specify a path to an array followed by .splices as an argument to the observer function.
Therefore, remove the selectedItems property and add a manual observer like so:
observers: [
'_selectedItemsChanged(selectedItems.splices)'
],

Related

Angular ng-repeat rendering issue for small lidt

I have the 2 of objects below:
$scope.MyObj_1={
Id:"1",
Title:"Title1",
Items:[
{
Id:"1",
Comment:"Simple comment 1",
}
]
};
$scope.MyObj_2={
Id:"2",
Title:"Title1",
Items:[
{
Id:"2",
Comment:"Simple comment 2",
},
{
Id:"3",
Comment:"Simple comment 3",
},
{
Id:"4",
Comment:"Simple comment 4",
}
]
};
And I have this html template (just to simplify):
<ul>
<li ng-repeat="note in MyObj.Items" >{{item.Comment}}</li>
</ul>
When I set MyObj with MyObj_1 value and then I set MyObj with MyObj_2 I am getting rendering problem related to the slowness of ng-repeat. In fact ng-repeat starts by adding items of MyObj_2 and then removes the item related to MyObj_1.
I tried ng-cloak and $timeout but the behavior still the same.
I am wondering why ng-repeat did not remove old element first and then push new elements.
Angular.copy makes clone of object from source to destination.It deletes all objects from destination object and then copy properties from source.
Angular.merge appends the source object to destination.If destination object already has elements, it will remain there and new properties from source object will add to destination object.
The behavior is expected if you set the $scope.MyObj_2 = $scope.MyObj_1;
Then they will point to the same reference in memory.
What you need to use is angular.copy() which creates a deep copy of source like this
$scope.MyObj_2 = angular.copy($scope.MyObj_1);
Also, in the repeat you have a typeo, should be
<ul>
<li ng-repeat="note in MyObj.Items" >{{note.Comment}}</li>
</ul>

How to add an if-clause using $scope derived from AngularJS in JSON-data?

Being a newbie in AngularJS and JSON, I have the following JSON-code:
{
key: 'EI',
value: 'Eingepasst',
rate: Settings.get('partnerRate'),
variants:
[
{ key: 'E0', value: 'Regulär', multiplier: 1, rate: Settings.get('partnerRate') }
]
},
However it should only be "used" in case a specific variable in AngularJS-code (to be detailed $.scope.something) gets a specific value.
How can I add such an if-clause herein (if possible)?
You can use ng-if in your html where you are binding your json data.
So let's say you have a div that is bound to some of the properties on your model, you can wrap that all in a div that has ng-if on it as follows:
<div ng-if="something === expectedValue">
<div>{{obj.rate}}</div>
<div>{{obj.value}}</div>
</div>
This is a pretty primitive example, but if you have "something" defined on your $scope it should work.

Extending UI-Router-Tabs To Display Form Validation State

I'm pretty new to Angular and having a problem figuring out how to bind a value from a data service to a customization of the https://github.com/rpocklin/ui-router-tabs project that I have created.
The customization is to display an icon in the tab heading that toggles based on the validation state of the corresponding ui-view. I've wired up a data service that is updated when validation succeeds or fails, and the binding is being "seen" by the controller that renders the tabs.
The problem arises when I attempt to pass this value into the tab data as "options". The value change/icon toggle is not being processed as the validation state changes. If I pass a hard-coded "true" into the tab data, the desired icon is displayed.
vm.tabs = [
{
heading: "View 1",
route: "manage.view1",
options: {
status: vm.stateService.getForm1State()
}
},
{
heading: "View 2",
disable: vm.disableTabs,
route: "manage.view2",
options:{
status: true
}
}
];
This doesn't seem like something that should be that difficult, so I think I'm just missing something obvious about the scoping. Here is a plunk http://plnkr.co/edit/iefvwcffSZmpfy83NGde?p=preview that demonstrates the issue.
Note: should be tagged as ui-router-tabs, but I lack the reputation to create the tag.
The problem lies here:
options: {
status: vm.stateService.getForm1State()
}
Since stateService.getForm1State() returns a boolean value, this value will be copied and assigned as the value of the status property.
So when this code has executed once it will for example be:
options: {
status: false
}
The options object won't react to any changes within the stateService.
An easy solution is to have stateService.getForm1State() return an object instead.
For example:
function stateService() {
var form1IsValid = {
status: false
};
return {
getForm1State: getForm1State,
setForm1State: setForm1State
};
function getForm1State() {
return form1IsValid;
}
function setForm1State(newValue) {
form1IsValid.status = newValue;
return;
}
Then make the options object refer to the same object:
options: vm.stateService.getForm1State()
Now whenever you have:
options.status
It will be the same as:
vm.stateService.getForm1State().status
And it will correctly reflect the changes.
Demo: http://plnkr.co/edit/KjXVSSMJbLw7uod0ac6O?p=preview

extracting information from array using knockout

I currently have an array being passed into my function and i wanted to pull out the information from the array so i can display it on the page.
This is what the array looks like:
EducationalClasses:[object, object]
first object contains:
classId: "324342",
className: "English 101"
second object contains:
classId: "231243",
className: "Reading"
when i do educationalClasses[0] i get the results as in first object. I wanted to create some sort of loop so that in my view page when i have:
<!-- ko foreach: educationalClasses -->
<div data-bind="text: className></div>
<!--/ko-->
i would get English 101 and Reading displayed
This is what i have for my viewModel:
viewModel = function(educationalClasses){
....
self.className= ko.observable(educationalClasses.className); // what i want
}
How can i do this properly and so that all the items in the array are displayed without me having to use educationalClasses[0].className...educationalClasses[1].className
Technically, you don't need any observables for what you're doing here. You just need your viewmodel to have a member named educationalClasses that is an array (or observableArray). You can just wrap your raw data in an object, label it, and it goes.
If you want to change the array and have the view show the updates, you'll want an observableArray. If you want changes to the individual data items to show, you'd want them to be observables as well.
rawData = [{
classId: "324342",
className: "English 101"
}, {
classId: "231243",
className: "Reading"
}];
viewModel = function(educationalClasses) {
return {
educationalClasses: educationalClasses
};
};
ko.applyBindings(viewModel(rawData));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<!-- ko foreach: educationalClasses -->
<div data-bind="text: className"></div>
<!--/ko-->

Path notification for changes to an object within an array?

We have a large model object that is owned and managed outside of polymer. We want to expose this model to polymer elements through a proxy element that exposes computed parts of it.
For example, the model may have:
{
blocks: {
...
properties: [
{ ... }, // prop0
{ ... }, // prop1
]
},
}
We are using recursive object observers and array observers to monitor changes to the model and notify polymer appropriately (either using .notifyPath(path, ...) for object changes and ._notifySplice(...) for array changes). However, there doesn't seem to be a good way for us to notify of changes to an object within an array, e.g. prop0 changed in the example above.
Is there? What should the path be?
Here's an example using binding to show an updated Polymer property nested inside an object and array:
code:
<div>
<h1>[[blocks.properties[0]]]</h1>
<p>this updated property should read: Apple</p>
</div>
script:
Polymer({
is: "my-page",
properties: {
blocks: {
type: Object,
value: { properties : ["acorn","banana","carrot"] },
notify: true
},
},
attached: function() {
console.log("update");
this.set('blocks.properties[0]', "Apple");
},
If you need to do array functions you should also use this.push(path, value) or this.splice(path, value) to notify changes.

Resources