I am using angluar js. On my page I have a table. Each record in the table has a col that is a drop down list. When this value gets changed and the user clicks save, the page checks to see if the value in the drop down has already been used. If it has, an alert message is presented and if not, then some code is executed. My problem is when the alert/error message is displayed. When this is displayed, I don't want the table to update according to the new value but it still does. How can I prevent this? I am really new to using angular.
$scope.saveDeviceUpdate = function (updatedDevice, deviceId) {
var numDevicesForBus = 0;
for (var i = 0; i < $scope.data.deviceList.length; i++)
{
if ($scope.data.deviceList[i].BusNumber == updatedDevice.busNumber)
{
numDevicesForBus++;
}
}
if (numDevicesForBus == 0)
{
dataService.updateDevice(updatedDevice, deviceId);
}
else
{
alert("This bus already has a device!");
}
};
Related
In an Angular application I have a form filters (multi select directive). Whenever a filter value is selected, it has to be included in the URL.
The goal is to be able to copy the URL with the form parameters and values and being able to send it to another client. In this way the second client would open the same page and all its fields would be already filled with the same values used by the first client.
At the moment every value selection triggers a function that encodes the parameter and the relative value and adds it to the current URL.
function obj_to_query(obj) {
var parts = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
for (var i = 0; i < obj[key].Keys.length; i++) {
if (encodeURIComponent(obj[key].FilterType) == 1) {
parts.push(encodeURIComponent("areas=" + obj[key].Keys[i]));
}
else if (encodeURIComponent(obj[key].FilterType) == 2) {
parts.push(encodeURIComponent("categories=" + obj[key].Keys[i]));
}
}
}
}
return "?" + parts.join('&');
}
Is there a better way to achieve the same result?
There is a review and approval workflow
On the start forms are attached files and selected executors(Package Items and People selection).
Then create a task is assigned to the previously selected executors.
Each executor sees the task assigned to it, and file attachments.
I need to check for adding files. While the executor has not added a file it can not approve the task.
I created the counter at the time of task creation taskListener event="create".
He counts the files sent to the executor.
Then I created another counter at the time of completion of the task taskListener event="complete", It also counts files.
Then I compare these two counters and if they are equivalent
It means that the executor does not attach files and he sees the error.
But this method works only for the first executor who approved the task.
The rest of the executors can already approve the task without adding files.
I do not know what the problem is.
Here's the code where I implemented it:
<userTask id="userTask5" name="Revies" activiti:assignee="${zvernennya_reviewnachassignee.properties.userName}" activiti:formKey="zvernennya:reviewnach">
<documentation>Review task</documentation>
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[
if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate;
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;;
var count=0;
for (var i = 0; i < bpm_package.children.length; i++)
{
count++;
}
execution.setVariable ('count', count);
]]></activiti:string>
</activiti:field>
</activiti:taskListener>
<activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[
if(task.getVariableLocal('zvernennya_reviewnachtransitions') == 'Approve') {
execution.setVariable('zvernennya_reviewnachapprovalcount', zvernennya_reviewnachapprovalcount + 1);
}
var count_new=0;
for (var i = 0; i < bpm_package.children.length; i++)
{
count_new++;
}
if (count==count_new) {
var message = "\n\nAttach files!!\n";
throw new Error(message + "\n");
}
]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="zvernennya_executers" activiti:elementVariable="zvernennya_reviewnachassignee">
<completionCondition>${zvernennya_reviewnachapprovalcount >= zvernennya_reviewnachrequiredapprovalcount}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
I think you need to re-initialize the variable "count" in the 2nd tasklistener ("complete"). like so:
var count = execution.getVariable ('count');
var count_new= bpm_package.children.length;
if (count==count_new) {
var message = "\n\nAttach files!!\n";
throw new Error(message + "\n");
}
Our project is using a custom filter to provide sorting and filtering of items in a list. It takes two arguments, the list, and a filter type parameter that determines the sort/filter scheme to apply. The filter appears to be responsible for a "10 $digest() iterations reached" error in Internet Explorer (only). The business end of the filter is below:
return function(players, filterType) {
switch (filterType) {
case 'Money':
return players.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPrizeMoney == b.WinnerPrizeMoney) return 0;
if (b.IsSelf || a.WinnerPrizeMoney < b.WinnerPrizeMoney) return -1;
if (a.IsSelf || a.WinnerPrizeMoney > b.WinnerPrizeMoney) return 1;
return 0;
});
case 'Tracked Players':
var trackedPlayers = [];
for (var i = 0; i < players.length; i++) {
if (players[i].IsTracked || players[i].IsSelf) {
trackedPlayers.push(players[i]);
}
}
return trackedPlayers;
case 'Connections':
var connectedPlayers = [];
for (var j = 0; j < players.length; j++) {
if (players[j].IsConnected || players[j].IsSelf) {
connectedPlayers.push(players[j]);
}
}
return connectedPlayers;
case 'Rank':
return players.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPosition == b.WinnerPosition) return 0;
if (b.IsSelf || a.WinnerPosition < b.WinnerPosition) return -1;
if (a.IsSelf || a.WinnerPosition > b.WinnerPosition) return 1;
return 0;
});
default:
}
};
Two of the filter types sort the items, the other two filter the items. The problem presents almost as soon as the page loads and gets items to filter, and initially the filterType is set to 'Rank'.
I have read that array.sort modifies the array in place, (i.e. it does not return a new array). Is my understanding on that count correct? .sort would not cause this problem as it is returning the same array it came in with, the items are just changed in position. That applies to filterTypes of 'Money' and 'Rank'.
For 'Tracked Players' and 'Connections' is there a better way to handle those than by creating a new array and pushing specific items into it according to the filter? While this does not appear to be the culprit in this instance, it seems to fit the mold that others have suggested as possible causes in other SO articles regarding this error.
I feel like I am spinning my wheels on this, I spent about 6 hours yesterday ("after work") fiddling with this trying to diagnose and fix it. I have narrowed it down to the filtering mechanism above, but other than that, I am having no luck.
Update
This seems to have specifically to do with Internet Explorer. I tested the filter in Chrome and Firefox and it was only hit once per filterType change (e.g. user changes the value of the Filter dropdown which in turn changes the filterType and fires off the filter.
Internet Explorer however repeatedly hits the filter. And only when filterType = 'Rank'. I don't get that though. Rank and Money have almost the exact same sorting scheme, just on different properties.
Just to be sure that this did not have something to do with the fact that I set filterType = 'Rank' in the initialization of the controller, I changed it to all three of the other values in turn. No problems. This now seems specifically to do with possibly the comparison of the values WinnerPosition (numeric) or with some value somehow changing on the item being sorted.
Stepping Through Execution Update
OK, so I may need someone to enlighten me. The $watchCollectionWatch function (angular.js:12307 in my case) iterates through the items in each collection on the scope and checks the oldValue (i.e. what was passed into the filter in this case) with the newValue (what came back) if the two are different it increments changeDetected signaling that a collection has changed. When a collection changes that has a filter on it, it re-runs the filter. In my case I am changing the ordering of the collection and thus every time the filter gets run, it reads it as having changed. How to get around this?
I ended up changing this around so that instead of having the filter above registered as such with the app, I put it on the controller called by ng-change on the drop down that the user specifies the filter with.
I changed the code a little. I store Players in both $scope.Players and $scope.StoragePlayers. StoragePlayers holds the empirical set of Players. $scope.Players is what the list of players on the page is bound to. I modify $scope.Players and only read from $scope.StoragePlayers.
New Version
$scope.NewFilter = function () {
switch ($scope.SelectedFilter) {
case 'Money':
$scope.Players = $scope.StoragePlayers.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPrizeMoney == b.WinnerPrizeMoney) return 0;
if (b.IsSelf || a.WinnerPrizeMoney < b.WinnerPrizeMoney) return -1;
if (a.IsSelf || a.WinnerPrizeMoney > b.WinnerPrizeMoney) return 1;
return 0;
});
break;
case 'Tracked Players':
var trackedPlayers = [];
for (var i = 0; i < $scope.StoragePlayers.length; i++) {
if ($scope.StoragePlayers[i].IsTracked || $scope.StoragePlayers[i].IsSelf) {
trackedPlayers.push($scope.StoragePlayers[i]);
}
}
$scope.Players = trackedPlayers;
break;
case 'Connections':
var connectedPlayers = [];
for (var j = 0; j < $scope.StoragePlayers.length; j++) {
if ($scope.StoragePlayers[j].IsConnected || $scope.StoragePlayers[j].IsSelf) {
connectedPlayers.push($scope.StoragePlayers[j]);
}
}
$scope.Players = connectedPlayers;
break;
case 'Rank':
$scope.Players = $scope.StoragePlayers.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPosition == b.WinnerPosition) return 0;
if (b.IsSelf || a.WinnerPosition < b.WinnerPosition) return -1;
if (a.IsSelf || a.WinnerPosition > b.WinnerPosition) return 1;
return 0;
});
break;
default:
}
I'm using ObjectEvents to give ActivityPoints to current user based on fields user filled.
Now for example if user register and fill FirstName I will give 10 points to user.
The problem is that I'm handling ObjectEvents.Update.After and inside it I'm updating userSettings.This causes a unlimited loop and application stops working.
is there any work around?
this is the code block:
var className = e.Object.TypeInfo.ObjectClassName;
DataClassInfo dci = DataClassInfoProvider.GetDataClass(className);
if (dci != null)
{
var fi = new FormInfo(dci.ClassFormDefinition);
if (fi != null)
{
var stopProccess = true;
var fields = new List<FormFieldInfo>();
foreach (var changedColumn in e.Object.ChangedColumns())
{
var field = fi.GetFormField(changedColumn);
var activityPointMacro = ValidationHelper.GetString(field.Settings["ActivityPointMacro"], "");
if (!string.IsNullOrEmpty(activityPointMacro))
{
fields.Add(field);
stopProccess = false;
}
}
if (!stopProccess)
{
var contextResolver = CMSContext.CurrentResolver.CreateContextChild();
foreach (FormCategoryInfo info in fi.ItemsList.OfType<FormCategoryInfo>())
{
contextResolver.SetNamedSourceData(info.CategoryName, info);
}
EditingFormControl data = new EditingFormControl();
foreach (FormFieldInfo info2 in fi.ItemsList.OfType<FormFieldInfo>())
{
contextResolver.SetNamedSourceData(info2.Name, data);
}
foreach (var field in fields)
{
{
var activityPointMacro = ValidationHelper.GetString(field.Settings["ActivityPointMacro"], "");
var activityPoint =
ValidationHelper.GetInteger(contextResolver.ResolveMacros(activityPointMacro), 0);
CMSContext.CurrentUser.UserSettings.UserActivityPoints += activityPoint;
CMSContext.CurrentUser.UserSettings.Update();
}
}
}
}
}
If you just need to give points for user fields then you could just use ObjectEvents.Update.Before, check fields are not empty and assign points. But i can see from the code, you want to have something more complex bulit over macro expressions. So I have a few suggestions for you.
1) ObjectEvents.Update.Before instead of ObjectEvents.Update.After still may be a good idea. Ideally you set your additional values and all is set during one update.
2) Watch only the class names you need
3) Always prefer Provider.SetInfo methods over info.Update(). In case of user settings it's best to set whole user info, so UserInfoProvider.SetUserInfo. Provider methods may add some additional important logic.
4) The code seems like it'll add the points with every update of a user
5) if you are still running into a loop, you need to flag somehow, that some part of code should not be executed again. The best way is to use RequestStockHelper class - add a bool value with a specificname like "PointsProcessed".
So I have this Array, named combo. I want to fill it with movieclips according to the user clicks (if user clicks 1, then add "1" to the Array and display it on an area.
Problem is, I do not know how to do it.
For the record, I have 4 movieclips, fire, wind, earth and spirit. When the user clicks one of them, I want the Array to update. Array's max length is 6 and it is always checked against a "true_combo" Array.
My questions are:
1) How do I remove the oldest item in the Array if the length has reached 6?
2) How do I display the movieclips one next to another (smaller versions of the buttons, not new movieclips), according to Combo?
3) How do I dynamically update the movieclip list on the stage?
This is a stripped version of my current fla
https://www.dropbox.com/s/17d9rgclz29ft1u/Untitled-1.fla
This is the code to check the combo against true combo:
function checkthis(e:Event)
{
if(combo.length == truecombo.length)
for(var o:int = 0; o < combo.length; o++)
{
if(combo[o] == truecombo[o])
{
bravo.play();
}
}
}
1
You can use the Array.shift() (remove first item in array) or Array.pop() (remove last item in array)
2 / 3
Use a for-loop and change the position of the items according the array. I assume the items in the array are references to the movieclips, then this would be functions you could use.
function add(clip:DisplayObject)
{
if (this.combo.length >= 6)
{
// remove child and remove it from the list
removeChild(this.combo.shift());
}
this.combo.push(clip);
this.addChild(clip);
reorder();
}
function reorder()
{
for(var i:int = 0; i < combo.length; i++)
{
combo[i].x = i * 50;
}
}
update:
You can download an example of this implementation here (Flash CS6 file) or watch it here
update 2
function checkthis(e:Event)
{
var isValid:Boolean = true;
if(combo.length == truecombo.length)
{
for(var o:int = 0; o < combo.length; o++)
{
if(combo[o] != truecombo[o])
{
// if one item isnt the same it should fail.
isValid = false;
}
}
}
if (isValid)
{
bravo.play();
}
}