forked from myplanet/angular-action
-
Notifications
You must be signed in to change notification settings - Fork 0
/
angular-action.js
124 lines (104 loc) · 4.63 KB
/
angular-action.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([ 'module', 'angular' ], function (module, angular) {
module.exports = factory(angular);
});
} else if (typeof module === 'object') {
module.exports = factory(require('angular'));
} else {
if (!root.mp) {
root.mp = {};
}
root.mp.action = factory(root.angular);
}
}(this, function (angular) {
'use strict';
return angular.module('mp.action', [])
.directive('do', function () {
return {
restrict: 'A',
scope: true,
// @todo eliminate the "then" attribute and just chain promises elsewhere
controller: [ '$scope', '$element', '$attrs', '$q', function (childScope, $element, $attr, $q) {
var doExpr = $attr['do'],
thenExpr = $attr.then,
action;
childScope.$action = action = {
isPending: false,
error: null,
invoke: function () {
action.isPending = true;
action.error = null;
var valueMap = {},
collectionFailed = false;
// broadcast to collect values from parameters
childScope.$broadcast('$actionCollecting', function (key, value) {
valueMap[key] = value;
}, function () {
collectionFailed = true;
});
if (collectionFailed) {
action.isPending = false;
return;
}
$q.when(childScope.$eval(doExpr, { $data: valueMap })).then(function (data) {
childScope.$eval(thenExpr, { $data: data });
}, function (error) {
action.error = error;
})['finally'](function () {
action.isPending = false;
});
},
reset: function () {
// only reset if not already pending
if (action.isPending) {
throw new Error('cannot reset pending action');
}
action.error = null;
childScope.$broadcast('$actionReset');
}
};
} ]
};
})
.directive('parameter', function () {
return {
restrict: 'A',
scope: true,
controller: [ '$scope', '$element', '$attrs', function (childScope, $element, $attr) {
if (!$attr.hasOwnProperty('collect')) {
throw new Error('The collect attribute is mandatory');
}
var name = $attr.parameter,
state = {
value: childScope.$parent.$eval($attr.value),
error: null
},
collectExpr = $attr.collect;
childScope.$actionData = state;
// report latest value before submitting
childScope.$on('$actionCollecting', function (event, reportValue, reportError) {
state.error = null;
var collectValue;
if (collectExpr) {
try {
collectValue = childScope.$parent.$eval('$value | ' + collectExpr, { $value: state.value });
} catch (e) {
state.error = e;
reportError();
return;
}
} else {
collectValue = state.value;
}
reportValue(name, collectValue);
});
// re-evaluate source value
childScope.$on('$actionReset', function () {
state.value = childScope.$parent.$eval($attr.value);
state.error = null;
});
} ]
};
});
}));