How can I link paths so results are updated in dom-repeat - polymer

I am developing an appointment booking system. It basically consists of a set of Polymer custom elements arranged as follows (indented elements are in the template of the element rather than actually organised as shown)
<my-appointments>
<person-appointment booking="{{booking}}>
<booking-type type="{{booking.type}}">
<div>[[booking.type]]</div>
</booking-type>
</person-appointment>
<appointment-day booking="{{booking}}>
<template is="dom-repeat" items="{{appointments}} as="{{appointment}}">
<div>[[appointment.type]]</div>
</template>
</appointment-day>
</appointment>
inside the <appointment-day> element booking is defined as an "Object" property and appointments as an "Array". As a booking is made, the booking object is spliced into the appointments array at the correct place.
At the same time I use the linkPaths function to join path 'booking' to path 'appointments.n' (where n is 0, 1, 2 etc for where in the appointments array booking is situated)
This is the code that does this
if (foundAppointment) {
//found where to insert appointment, so do so
this.splice(path, j, 0, this.booking);
this.linkPaths('booking', path + '.' + j);
this.linkedBooking = true;
break;
}
Not shown is a mechanism inside <booking-type> to update the type property. SO when I update the type property using this mechanism, the visual representation changes inside the <person-appointment> element but it does not change inside the dom-repeat. I can check that the object located at appointents[n] IS updated, but the display is not updated.
I presume I haven't properly linked booking to the appropriate appointment entry. BUT how should I achieve this

Polymer does not observe the change of sub-properties of appointments.
Try to Force data system to pick up array the mutations with the code below:
// Force data system to pick up the **array** mutations
var array = this.appointments;
this.appointments= [];
this.appointments= array;
Try to add this to your code.
if (foundAppointment) {
//found where to insert appointment, so do so
this.splice(path, j, 0, this.booking);
this.linkPaths('booking', path + '.' + j);
this.linkedBooking = true;
// Force data system to pick up array mutations
var array = this.appointments;
this.appointments= [];
this.appointments= array;
break;
}
Or to Force data system to pick up the Object mutations with the code below:
// Force data system to pick up array mutations
var object = this.appointment;
this.appointment= [];
this.appointment= object;

I'm only guessing that the problem is in binding to array items.
Polymer has special rules for that.
Here is one example of array binding: Plunk
<template is="dom-repeat" items="[[first4People(people, people.*)]]">
<div>
Index: <span>[[index]]</span>
<br>
First as this:[[arrayItem(people.*, index, 'first')]]
<br>
First not as this: <span>[[item.first]]</span>
</div>
<br><br>
</template>
Simplified online example of the problem would help to understand the issue better.

Related

Is there a way of searching div element by class in GAS? [duplicate]

Is there a simple method to locate an XML node by its attribute in Google Apps Script? Here's an XML snippet:
<hd:components>
<hd:text name="ADM Custom admissions TE">
<hd:prompt>Admission</hd:prompt>
<hd:columnWidth widthType="minimum" minWidth="100"/>
</hd:text>
<hd:text name="ADM Insufficient heat end date TE">
<hd:prompt>To</hd:prompt>
</hd:text>
<hd:text name="ADM Insufficient heat start date TE">
<hd:prompt>From</hd:prompt>
</hd:text>
<hd:text name="ADM Third party payment period TE">
<hd:defMergeProps unansweredText="__________"/>
<hd:prompt>When (date or period)?</hd:prompt>
</hd:text>
For purposes of the XML file I'm trying to parse, the "name" attribute is a unique identifier, while what GAS thinks is the "name" for purposes of the XmlService.Element.getChild(name) method ("text" for each node shown in this snippet) is a non-unique classifier for the type of node. I'd like to be able to write a function to retrieve a specific node from this XML file with only the name attribute. XMLPath notation in other languages has this capability using the [# notation. Is there a way to do it in GAS, or do I need to write a function that walks through the XML until it finds a node with the right name attribute, or store it in some different type of data structure for fast searching if the XML file is sufficiently large?
Here's the snippet I started writing: it's fine if there's no built-in function, I just wondered if there was a better/faster way to do this. My function isn't so efficient, and I wondered if the XmlService had a more efficient internal data structure it's using to speed up searching. My approach is just to loop through all of the element's children until there's a match.
function getComponentFromXML(xml,name) {
for (var i = 0; i < xml.length; i++) {
var x = xml[i];
var xname = x.getAttribute('name').getValue();
if (xname == name) {
return getComponentAttributes(x);
}
}
}
There is no built-in search, so the only way is to read the list of elements looking for the one with the desired value of attribute 'name'. If elements is an array of elements to search through, you can do
var searchResults = elements.filter(function (e) {
return e.getAttribute('name') && e.getAttribute('name').getValue() == searchString;
});
(Both checks are needed to avoid an error when there is no 'name' attribute at all.)
How to obtain such an array elements may depend on XML document. If, as in your example, the elements to search are the immediate children of the root element, then
var doc = XmlService.parse(xmlString);
var elements = doc.getRootElement().getChildren();
would be a quick and easy way to do this.
In general, to get all elements without recursion, the getDescendants method can be used. It returns an array of Content object, which can be filtered down to Element objects:
var elements = doc.getDescendants().filter(function (c) {
return c.getType() == XmlService.ContentTypes.ELEMENT;
}).map(function (c) {
return c.asElement();
});

onClick is always returning 25

I'm using reactjs.
I have a series of divs that are created that represent a employee's availability. When clicked, they will display the number. However, they all alert the number 25 instead of their number.
for (
var i = state.availability[day][0];
i <= state.availability[day][1];
i++
) {
tempdaySlot.push(
<div
key={"ena:" + TimeConverter(i)}
style={LocalStyles.daySlot}
onClick={() => alert(i)}
>
{TimeConverter(i)}
</div>
);
}
state.availability is a two dimensional array that holds a number between 1-24 that represents someone's availability (ex [9-17])
TimeConverter is a function that converts a 24 hour type number to the usual 12 hour format (17 = "5 pm")
tempdaySlot is just a temporary array before I put it into a state variable
Use let i instead of var i. var hoists variable to the parent scope, let creates block scope.
this is a hoisting issue, because you defined the i using var it will be hoisted to the top of the function body so the last value which is 25 will be the only thing stored in that variable and since the variable isn't destroyed because it's hoisted it will only show the latest value.
just use let instead of var its a good practice to use let and const instead of var now so try getting used it, it will save you a lot of headaches.
Tl;dr declare i using let, not var
The var keyword creates variables with function scope. However, when you create a closure (like your onClick function), the lexical environment is captured by reference. When you call that onClick function later, it gets the current value of i (which is 25, since that's where the loop stopped), not the value of i when you created the function.
The let keyword creates i with traditional scoping, so in effect a new i is created on each iteration of the loop which solves this problem.
See What's the difference between using "let" and "var"? for more.

getting a random element from an array of movieclips(or labels in a timeline) in Flash CC . Actionscript 3

I am making a pretty neat quiz-game in flashCC right now and I definitely need your help.
My skills are more on the design then the programming side. So to many of you this might seem a baby question (and asked many times before) but from all the answers I saw so far, I couldn't get any results for my project.
So here is the thing :
I need the EXACT script for creating an array (with movieclips inside? or instance names of mcs? How does this even work?)
and a method, to pick a random element of this array without repeats until the "game is over".
Paul
The easiest way to pick a random element from an array without repeating is to first sort the array with a "random" function, then pop or shift items out of it until the array is empty.
Let's say you have an array of items which can be filled with either instances or instance names, you've chosen instance names: :
var FirstArray:Array = ["blau", "orange", "green"];
Now, you'll need a random sort function:
// you do not need to modify this function in any way.
// the Array.sort method accepts a function that takes in 2 objects and returns an int
// this function has been written to comply with that
function randomSort(a:Object, b:Object):int
{
return Math.random() > .5 ? -1 : 1;
}
The way a sort function normally works is it compares two objects and returns -1 if the first item precedes the second item, 1 if the opposite is true, and 0 if they are the same.
So what we're doing in the function above is returning -1 or 1 randomly. This should get the array all jumbled up when you call:
FirstArray.sort(randomSort);
Now that the array is randomly sorted, you can begin pulling items from it like so:
if(FirstArray.length) // make sure there's at least one item in there
{
// since you are using instance names, you'll need to use that to grab a reference to the actual instance:
var currentQuizItem:MovieClip = this[FirstArray.pop()];
// if you had filled your array with the actual instances instead, you would just be assigning FirstArray.pop() to currentQuizItem
// every time you call pop on an array, you're removing the last item
// this will ensure that you won't repeat any items
// do what you need to do with your MovieClip here
}
else
{
// if there aren't any items left, the game is over
}
When strung together, the above code should be enough to get you up and running.
You could try something like:
var array:Array = [1, 2, 3, 4, 5];
var shuffledArray:Array = [];
while (array.length > 0)
{
shuffledArray.push(array.splice(Math.round(Math.random() * (array.length - 1)), 1)[0]);
}
trace('shuffledArray: ', shuffledArray, '\nrandom item: ', shuffledArray[0]);

Splice then re-index array in ActionScript 3

I want to remove the first four indexes from the array using splice(), then rebuild the array starting at index 0. How do I do this?
Array.index[0] = 'one';
Array.index[1] = 'two';
Array.index[2] = 'three';
Array.index[3] = 'four';
Array.index[4] = 'five';
Array.index[5] = 'six';
Array.index[6] = 'seven';
Array.index[7] = 'eight';
Array.splice(0, 4);
Array.index[0] = 'five';
Array.index[1] = 'six';
Array.index[2] = 'seven';
Array.index[3] = 'eight';
I am accessing the array via a timer, on each iteration I want to remove the first four indexes of the array. I assumed splice() would remove the indexes then rebuild the array starting at 0 index. it doesn't, so instead what I have done is created a 'deleteIndex' variable, on each iteration a +4 is added to deleteIndex.
var deleteIndex:int = 4;
function updateTimer(event:TimerEvent):void
{
Array.splice(0,deleteIndex);
deleteIndex = deleteIndex + 4;
}
What type of object is "Array" in the code you have shown? The Flash Array object does not have a property named "index". The Array class is dynamic, which means that it let's you add random properties to it at run time (which seems to be what you are doing).
In any case, if you are using the standard Flash Array class, it's splice() method updates the array indexes automatically. Here is a code example that proves it:
var a:Array = [1,2,3,4,5];
trace("third element: ", a[2]); // output: 3
a.splice(2,1); // delete 3rd element
trace(a); // output: 1,2,4,5
trace(a.length); // ouput: 4
trace("third element: ", a[2]); // output: 4
If I am understanding what you want correctly, you need to use the unshift method of Array.
example :
var someArray:Array = new Array(0,1,2,3,4,5,6,7,8);
someArray.splice(0,4);
somearray.unshift(5,6,7,8);
Also, you are using the Array Class improperly, you need to create an instance of an array to work with first.
The question is confusing because you used Array class name instead of an instance of an array. But as the commenter on this post said, if you splice elements, it automatically re-indexes.
im not sure what you want to do, but Array=Array.splice(0,4) should fix somethin..

Creating a user generated list in flash

I'm trying to create a flash application that will keep track of user generated values. The app should basically allow the user to input the name of the item and it's cost. The total costs should then be added up to show a total value to the user. I can probably figure out how to add the values together, but I'm not really sure how to allow the user to create a list and then allow the user to save it. Can anyone point me towards a tutorial or point me in the right direction?
I am using variables to add user inputed numbers to come up with a total. The first problem is that actionscript 3.0 does not allow variables for texts. I just converted it to 2.0 to fix this. The second problem, is when I test the app and put in my values and click submit, I get NaN in the total values field. Is there a reason why it wouldn't add the values?
Here is the code I used for the submit button:
on (release) {
total = Number(rent) + Number(food) + Number(travel) + Number(entertainment) + Number(bills);
}
Am I missing anything?
Can I give the input text instance names and then give them variables? How are some ways to go about this?
Thanks for the help!
Have an object array, say for example
var stack:Array = new Array();
Then push the item name and it's cost to that array when user inputs, like
stack.push({item:AAA, cost:xx});
So that you can generate the list whenever you want with that array.
You have to see how this works in code. A list in actionscript could be stored inside an array, vector, dictionary or even an Object.
Var myList:Array = [];
myList.push({name: "item 1", cost: 5 });
myList.push({name: "item 2", cost: 7.5 });
If you want to grab the 'product' of "item 1" from the list, you have to create a function for that, lets call it getProductByName
function getProductByName(name:String):Object
{
for each(var product:Object in myList)
{
if (product.name === name) return product;
}
return null; // no match found
}
You can call that function like this:
var product = getProductByName("item 1");
trace(product.cost); // 5
And you can alter the product, so lets make it more expensive
product.cost += 1;
trace(product.cost); // 6
Have fun! If you are using classes, you would create one for the product, with public name and cost, and in that case you'de better use a vector, to ensure working with the right type.
This is what fixed the issue for me in action script 3.0:
myButton.addEventListener(MouseEvent.CLICK, addThem);
function addThem(e:MouseEvent)
{
totalField.text = String ( Number(field1.text) + Number(field2.text) + ....);
}
I also had to name the instances appropriately.