AngularJS two way binding variables to array items - angularjs

To view my code follow this link
I've created a directive which handles an array of items (it will always be two because it's a "from" and "to" date pair).
I want to make the array items accessible as separate values for later use so I refer to the array items like this
vm.data = ['data a', 'data b'];
vm.separateData = vm.data[0];
vm.otherData = vm.data[1];
When I implement a two way bind into the directive, the vm.data[0] and vm.data[1] references are updated but the vm.separateData and vm.otherData aren't.
Is there a way of making this work or should I just restructure the rest of my app (where needed) to accomodate for array items?
In my fiddle link (same as above) try changing the text input values and you'll see what I mean.

vm.data[0] is a string and thus it is a primitive datatype in javascript which is immutable. So you bind the immutable String 'Data a' to vm.separateData, which is not a reference to data[0].
If you want to copy the reference to the array into vm.separateData try to wrap your strings in other javascript objects, e.g.
vm.data = [{"value":"Data a"}, {"value":"Data b"}]
and then you can reference
vm.separateData = vm.data[0];
and access the value via
vm.separateData.value

Related

Get stored index from object literal in angular 2

I have a stored object literal which returns 2 or more objects depending on the users actions. This is then filtered further depending on if they are complete or not, so there are generally 2 object arrays that are sent to the view.
in the view i do a simple ngFor
<ion-card *ngFor="let item of inProgressList">
...
Which is a segment of the complete list held in a variable programsList
In order to change an item from in progress to complete i need to update the object, which works fine, however i cannot correctly pass the index.
filledOutFormsData[this.index].complete = true;
As i cannot get the correct index based on the array that has been filtered.
I cannot use
<ion-card *ngFor="let item of inProgressList; let i = index">
Because that will return a index of the looped items which will be incorrect once one other object is equal to complete
Basically i need to get the object key from the original object literal into the filtered array to use in the view so that i can pass the index.
So i got this working by adding a custom pipe which filters the programsList instead of passing in two separate lists, I can then use the trackBy option to pass the correct index.

AngularJS custom SortBy

I have an array with several objects {id:x , name:y} retrieved from a Java Enum and I need to order them alphabetically, but one of the objects must mandatorily be in the bottom of the <select> comboBox, how could I achieve this result? I used ng-options with orderBy, but, I can't figure out how to put this particular object into the bottom.
The easiest way is to sort in the controller, when you get the data from the server:
find the "special" object that should go to the bottom and remove it from the array
sort the array, using $filter('orderBy')(array, 'name')
push the "special" object to the sorted array
expose the sorted array on the scope and use that array in ng-options

applying class in ng-repeat if contained in another array

I am querying for a collection of IDs from Parse.com and showing them in my $scope as an array.
I would like to apply a class to the items in my $scope that match any one of these IDs, placing a border around the object illustrating that it is already contained in the 'saved' array. I have tried the following however not having any luck.
ng-class="{'approved': ParseSavedExercises.indexOf(exercise.id) == -1}"
in this case my ParseSavedExercisesis my array to check against and exercise.id is what I am checking for.
here is a quick fiddle
Please see here http://jsfiddle.net/e9pr4yqj/
Yours ParseSavedExercises contains string and id is number so no id existed in ParseSavedExercises
$scope.ParseSavedExercises = ['2','3'];
change to
$scope.ParseSavedExercises = [2,3];
or use
ng-class="{'approved': ParseSavedExercises.indexOf(exercise.id.toString()) == -1}"
like here http://jsfiddle.net/1ujgvL80/

Make variable name using loop and string in PowerBuilder

I am interested if it is possible to make variable name in PowerBuilder using a loop and a string. For example:
long ll_go
string lst_new
for ll_go = 1 to 8
lst_new = "text" + ll_go
lst_new.tag = 5500
next
So, it should give me variables text1, text2..,.,text8 and I would be able to assign values for them. Let me know if anybody succeeded, thanks in advance
Your description is lacking some term precision.
If you actually want to dynamically create new variables as "variable in a powerscript subroutine or function" this is simply not possible.
If instead you want to create dynamically some new controls statictext or textedit objects in a window or visual userobject this is possible:
use a local variable of the type of the new object you need to create, e.g. static text
make it a live object (instantiate) with create
set the object properties to whatever you need
"attach" the new object to its parent (either a window or a visual userobject - though any graphicobject is possible with using the win32api SetParent function) with the OpenUserObject() method. Note that you cannot simply add it directly to the parent's Control[] array.
you can also keep the object in your own array for later convenience access to the created objects instead of looping on the Control[] array
once the object is attached it its parent, you can reuse the local variable to create another one
Here is an example:
//put this in a button clicked() event on a window
//i_myedits is declared in instances variables as
//SingleLineEdit i_myedits[]
SingleLineEdit sle
int i
for i = 1 to 8
sle = create singlelineedit
sle.text = string(i)
sle.tag = "text_" + string(i)
sle.height = pixelstounits(20, ypixelstounits!)
sle.width = pixelstounits(100, xpixelstounits!)
parent.openuserobject(sle, pixelstounits(10, xpixelstounits!), pixelstounits(22 * i, ypixelstounits!))
i_myedits[i] = sle //keep our own reference
next
An exemple of values access:
//put that in another button clicked() event
SingleLineEdit sle
int i
string s_msg
for i = 1 to upperbound(i_myedits[])
sle = i_myedits[i]
if i > 1 then s_msg += "~r~n"
s_msg += "edit #" + string(i) + " (" + sle.tag + ") says '" + sle.text + "'"
next
messagebox("Edits values", s_msg)
As you can see, one practicality problem is that you cannot refer to these controls by constructing the control's name like "text"+2, instead you must access the my edits[] array or loop through the controls and test their .tag property if you set it to something specific.
I do not think that it is possible. Workaround could be an array maybe.
Br. Gábor
I'd see two ways to do this, but they aren't as easy as it seems that you were hoping:
1. Control Array
First method would be to go through the control arrays (on windows, tabs and user objects). I'd create a function that took the control name as a string, then another that overloaded the same function and took control name and an array of windowobject. The string-only method would just call the string/array method, passing the string through and adding the window.Control as the second parameter. The string/array method would go through the array, and for each element, get the ClassDefinition. Pull the name off of it, and parse it apart the way you want it to match the string parameter (e.g. for w_test`tab_first`tabpage_first`cb_here, do you want cb_here to match, or tab_first`tabpage_first`cb_here?). Deal with matches as appropriate. When you find a control of type tab or user object, call the string/array function again with the Control array from that object; deal with success/fail returns as appropriate.
2. DataWindow
What you're describing works extremely well with DataWindows, and their Describe() and Modify() functions. Since you pass these functions only a string, you can build not only the control names, but the values they're set to as you would build any string. In fact, you can build multiple Modify() strings together (delimited by a space) and make a single call to Modify(); this is not only faster, but reduces window flicker and visible activity.
Don't fall into the trap of thinking that, since your data isn't from a database, you can't use a DataWindow. Create an external DataWindow, and simply use it with one row inserted during the Constructor event.
As you might guess, I'd strongly favour the DataWindow approach. Not only is it going to perform better, but it's going to provide a lot more flexibility when you want to move on and tag more control types than just static text. (You'll have to do some type casting even with one control type, but if you want to get into multiples, you'll need to start a CHOOSE CASE to handle all your types.)
Good luck,
Terry
You can't create a variable name in a script because the variables have to be declared before you can use them. With PBNI it's possible to generate a name the way you describe and then get a reference to a variable of that name that already exists but I don't think that's what you want. If you want to keep track of additional properties for your controls, just inherit a new user object from whatever it is (sle, mle, etc.) and add the properties you want. Then you can place your user object on a window and use the properties. Another approach is to use the control's Tag property. It holds a string that you can put whatever you want in. PFC uses this technique. Terry's DataWindow solution is a good approach for storing arbitrary data.
Yes, and there are more than one way to skin a cat.
Sounds like you have several properties so I'd use an array of custom non visual user objects, or an array of structures. Otherwise you could probably use something from the .NET framework like a dictionary object or something like that, or a datawidnow using an external datasource, where you can refer to column names as col + ll_index.ToString().
SIMPLE Example:
Make custom NVO with following instance variables, plus getter/setter functions for each, name it n_single_field
// add the properties and recommend getter and setter functions
public string myTag
public string myText
public int myTabOrder
...
// To USE the NVO define an unbounded array
n_single_field fields[]
// to process the populated fields
integer li_x, li_max_fields
// loop through field 1 through max using array index for field number
li_max_fields = upperbound(fields)
for li_x = 1 to li_max_fields
fields[li_x].myTag = 'abc'
fields[li_x].myText = 'text for field number ' + li_x.ToString()
fields[li_x].myTabOrder = li_x * 10
next
Maybe I'm oversimplifying if so let me know, if there is a will there is always a way. ;)

How do I add more meaningful names to ng-model bindings?

The code I am playing around with can be found here.
As of now, in all of my text fields, ng-model has only one name, fieldData. When I take the created javascript object and make it into a JSON object, I get the following:
[{"pHolder":"ID goes here","fieldData":"123"},{"pHolder":"Description goes here","fieldData":"456"},{"pHolder":"Drop Dead Date goes here","fieldData":"789"}]
Since each field has a different meaning, I would like that to be reflected in the bound name.
So instead of an array with three objects that each have the string called fieldData, I would like an array of three objects where foo bar and baz are substituted in each place where there is now fieldData.
How do I do that?
Javascript Array objects are quite flexible, as any other aspect of it, and you can use that to your advantage :) ngRepeat iterates through any array, be it ordered or associative (which are basically the same). So, if you change your array to:
$scope.entryFields = {
id: {pHolder:'ID goes here',fieldData:""},
description: {pHolder:'Description goes here',fieldData:""},
date: {pHolder:'Drop Dead Date goes here',fieldData:""}
};
The ng-repeat element will still work (you may want to reorder it, as it orders alphabetically by key name, by default) without any changes, but you can adress the fields by name (dot notation). See the updated fiddle here.

Resources