I am fairly new to Vue so excuse my stupidity!!
Can anyone tell me what I am doing wrong in my code below that is preventing me from getting my 'series_interactions_daily' variable data from inside the mounted() method please? I am console.log()'ing it but nothing shows! I can print 'series_interactions_daily' to screen in the HTML though!
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
let chart = am4core.create(this.$refs.chartdiv, am4charts.XYChart);
chart.paddingRight = 20;
let dummydata = [];
let visits = 10;
for (let i = 1; i < 366; i++) {
visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
dummydata.push({ date: new Date(2018, 0, i), name: "name" + i, value: visits });
}
chart.data = dummydata;
console.log(this.series_interactions_daily);
let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 35;
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "value";
series.tooltipText = "{valueY.value}";
chart.cursor = new am4charts.XYCursor();
let scrollbarX = new am4charts.XYChartScrollbar();
scrollbarX.series.push(series);
chart.scrollbarX = scrollbarX;
this.chart = chart;
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
}
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
total_interactions: '',
average_daily_interactions: '',
series_interactions_daily: [],
}
},
methods: {
onChange(event) {
this.$router.push('?range=' + event.target.value);
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?range=' + event.target.value)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
}
},
created() {
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
EDIT
OK, so I have create a method to fetchData() from mounted(){} - however I am still not getting my 'series_interactions_daily' variable data!
<script>
import * as am4core from "#amcharts/amcharts4/core";
import * as am4charts from "#amcharts/amcharts4/charts";
import am4themes_animated from "#amcharts/amcharts4/themes/animated";
am4core.useTheme(am4themes_animated);
export default {
mounted() {
this.fetchData();
let chart = am4core.create(this.$refs.chartdiv, am4charts.XYChart);
chart.paddingRight = 20;
let dummydata = [];
let visits = 10;
for (let i = 1; i < 366; i++) {
visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
dummydata.push({ date: new Date(2018, 0, i), name: "name" + i, value: visits });
}
chart.data = dummydata;
console.log(this.series_interactions_daily);
let dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 35;
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "value";
series.tooltipText = "{valueY.value}";
chart.cursor = new am4charts.XYCursor();
let scrollbarX = new am4charts.XYChartScrollbar();
scrollbarX.series.push(series);
chart.scrollbarX = scrollbarX;
this.chart = chart;
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
}
},
data() {
return {
campaign_id: this.$route.params.campaign_id,
campaign: [],
dateranges: [],
total_interactions: '',
average_daily_interactions: '',
series_interactions_daily: [],
}
},
methods: {
fetchData() {
this.$http.get('https://dev.local/api/portal/campaign/' + this.campaign_id + '?' + this.axiosParams)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
},
onChange(event) {
this.$router.push('?range=' + event.target.value);
this.$http.get('https://connie.laravel/api/portal/campaign/' + this.campaign_id + '?range=' + event.target.value)
.then(function(data){
return data.json();
}).then(function(data){
this.campaign = data.campaign;
this.dateranges = data.dateranges;
this.total_interactions = data.totalInteractions;
this.average_daily_interactions = data.averagreDailyInteractions;
this.series_interactions_daily = data.interactions_per_day.stats.interaction.daily;
});
}
},
created() {
},
computed: {
axiosParams() {
const params = new URLSearchParams();
if(this.$route.query.range) params.append('range', this.$route.query.range);
return params;
}
},
filters: {
},
directives: {
},
}
</script>
Any help appreciated.
Thanks,
K...
In fetchData, return the promise returned by the async $http call:
fetchData() {
return this.$http.get(...)
...
}
Now you can register a callback on that promise in mounted:
mounted() {
this.fetchData().then(result => {
...
});
}
Or just await it with async/await:
async mounted() {
await this.fetchData();
...
// Now everything will be ready
}
As #tao mentioned in comments, note that the await would delay any code that comes after it. If you don't have anything else to do in the hook anyway that's no problem but it's something to understand.
Related
I am getting a getSecondsUptime field when a component mounts, saving it to initialData and then want to increment that each second. However, I am getting an infinite loop warning and hundreds of console logs within seconds. I can't tell what I am doing wrong.
data() {
return {
time: 0,
}
},
mounted() {
this.time = this.$store.getters['into/getSecondsUptime'];
setInterval(this.calcTime, 1000)
},
methods: {
calcTime: function() {
console.log('foo');
this.time = this.time + 1;
let date = new Date(null);
date.setSeconds(this.time);
let result = date.toISOString().substr(11, 8);
return result;
}
}
you are calling your calcTime function multiple times. Maybe you can change to like this
mounted() {
this.time = this.$store.getters['into/getSecondsUptime'];
this.calcTime()
},
methods: {
calcTime: function() {
setInterval(() => {
this.time = this.time + 1
}, 1000);
}
}
You can call calcTime by Using window.setInterval which will be called every second. Like below
mounted() :{
this.time = this.$store.getters['into/getSecondsUptime'];
window.setInterval(() => {
this.calcTime();
}, 1000);
},
methods: {
calcTime() {
console.log('foo');
this.time = this.time + 1;
let date = new Date(null);
date.setSeconds(this.time);
let result = date.toISOString().substr(11, 8);
return result;
}
}
I am integrating Agora Web SDK with nuxt.js.
I have included all the methods I need and my page has the following methods and lifecycle hooks:
methods: {
streamInit(uid, attendeeMode, videoProfile, config) {
let defaultConfig = {
streamID: uid,
audio: true,
video: true,
screen: false
};
switch (attendeeMode) {
case "audio-only":
defaultConfig.video = false;
break;
case "audience":
defaultConfig.video = false;
defaultConfig.audio = false;
break;
default:
case "video":
break;
}
let stream = AgoraRTC.createStream(merge(defaultConfig, config));
stream.setVideoProfile(videoProfile);
return stream;
},
subscribeStreamEvents() {
let rt = this;
rt.client.on("stream-added", function(evt) {
let stream = evt.stream;
console.log("New stream added: " + stream.getId());
console.log("At " + new Date().toLocaleTimeString());
console.log("Subscribe ", stream);
rt.client.subscribe(stream, function(err) {
console.log("Subscribe stream failed", err);
});
});
rt.client.on("peer-leave", function(evt) {
console.log("Peer has left: " + evt.uid);
console.log(new Date().toLocaleTimeString());
console.log(evt);
rt.removeStream(evt.uid);
});
rt.client.on("stream-subscribed", function(evt) {
let stream = evt.stream;
console.log("Got stream-subscribed event");
console.log(new Date().toLocaleTimeString());
console.log("Subscribe remote stream successfully: " + stream.getId());
console.log(evt);
rt.addStream(stream);
});
rt.client.on("stream-removed", function(evt) {
let stream = evt.stream;
console.log("Stream removed: " + stream.getId());
console.log(new Date().toLocaleTimeString());
console.log(evt);
rt.removeStream(stream.getId());
});
},
removeStream(uid) {
this.streamList.map((item, index) => {
if (item.getId() === uid) {
item.close();
let element = document.querySelector("#ag-item-" + uid);
if (element) {
element.parentNode.removeChild(element);
}
let tempList = [...this.streamList];
tempList.splice(index, 1);
this.streamList = tempList;
}
});
},
addStream(stream, push = false) {
let repeatition = this.streamList.some(item => {
return item.getId() === stream.getId();
});
if (repeatition) {
return;
}
if (push) {
this.streamList = this.streamList.concat([stream]);
} else {
this.streamList = [stream].concat(this.streamList);
}
},
handleCamera(e) {
e.currentTarget.classList.toggle("off");
this.localStream.isVideoOn()
? this.localStream.disableVideo()
: this.localStream.enableVideo();
},
handleMic(e) {
e.currentTarget.classList.toggle("off");
this.localStream.isAudioOn()
? this.localStream.disableAudio()
: this.localStream.enableAudio();
},
switchDisplay(e) {
if (
e.currentTarget.classList.contains("disabled") ||
this.streamList.length <= 1
) {
return;
}
if (this.displayMode === "pip") {
this.displayMode = "tile";
} else if (this.displayMode === "tile") {
this.displayMode = "pip";
} else if (this.displayMode === "share") {
// do nothing or alert, tbd
} else {
console.error("Display Mode can only be tile/pip/share");
}
},
hideRemote(e) {
if (
e.currentTarget.classList.contains("disabled") ||
this.streamList.length <= 1
) {
return;
}
let list;
let id = this.streamList[this.streamList.length - 1].getId();
list = Array.from(
document.querySelectorAll(`.ag-item:not(#ag-item-${id})`)
);
list.map(item => {
if (item.style.display !== "none") {
item.style.display = "none";
} else {
item.style.display = "block";
}
});
},
handleExit(e) {
if (e.currentTarget.classList.contains("disabled")) {
return;
}
try {
this.client && this.client.unpublish(this.localStream);
this.localStream && this.localStream.close();
this.client &&
this.client.leave(
() => {
console.log("Client succeed to leave.");
},
() => {
console.log("Client failed to leave.");
}
);
} finally {
this.readyState = false;
this.client = null;
this.localStream = null;
// redirect to index
this.$router.push("/");
}
}
},
created() {
let $ = this;
// init AgoraRTC local client
$.client = AgoraRTC.createClient({ mode: $.transcode });
$.client.init($.appId, () => {
console.log("AgoraRTC client initialized");
$.subscribeStreamEvents();
$.client.join($.appId, $.channel, $.uid, uid => {
console.log("User " + uid + " join channel successfully");
console.log("At " + new Date().toLocaleTimeString());
// create local stream
// It is not recommended to setState in function addStream
$.localStream = this.streamInit(uid, $.attendeeMode, $.videoProfile);
$.localStream.init(
() => {
if ($.attendeeMode !== "audience") {
$.addStream($.localStream, true);
$.client.publish($.localStream, err => {
console.log("Publish local stream error: " + err);
});
}
$.readyState = true;
},
err => {
console.log("getUserMedia failed", err);
$.readyState = true;
}
);
});
});
},
mounted() {
this.$nextTick(() => {
// add listener to control btn group
let canvas = document.querySelector("#ag-canvas");
let btnGroup = document.querySelector(".ag-btn-group");
canvas.addEventListener("mousemove", () => {
if (global._toolbarToggle) {
clearTimeout(global._toolbarToggle);
}
btnGroup.classList.add("active");
global._toolbarToggle = setTimeout(function() {
btnGroup.classList.remove("active");
}, 2000);
});
});
},
beforeUpdate() {
let $ = this;
// rerendering
let canvas = document.querySelector("#ag-canvas");
// pip mode (can only use when less than 4 people in channel)
if ($.displayMode === "pip") {
let no = $.streamList.length;
if (no > 4) {
$.displayMode = "tile";
return;
}
$.streamList.map((item, index) => {
let id = item.getId();
let dom = document.querySelector("#ag-item-" + id);
if (!dom) {
dom = document.createElement("section");
dom.setAttribute("id", "ag-item-" + id);
dom.setAttribute("class", "ag-item");
canvas.appendChild(dom);
item.play("ag-item-" + id);
}
if (index === no - 1) {
dom.setAttribute("style", `grid-area: span 12/span 24/13/25`);
} else {
dom.setAttribute(
"style",
`grid-area: span 3/span 4/${4 + 3 * index}/25;
z-index:1;width:calc(100% - 20px);height:calc(100% - 20px)`
);
}
item.player.resize && item.player.resize();
});
} else if ($.displayMode === "tile") {
// tile mode
let no = $.streamList.length;
$.streamList.map((item, index) => {
let id = item.getId();
let dom = document.querySelector("#ag-item-" + id);
if (!dom) {
dom = document.createElement("section");
dom.setAttribute("id", "ag-item-" + id);
dom.setAttribute("class", "ag-item");
canvas.appendChild(dom);
item.play("ag-item-" + id);
}
dom.setAttribute("style", `grid-area: ${tile_canvas[no][index]}`);
item.player.resize && item.player.resize();
});
} else if ($.displayMode === "share") {
// screen share mode (tbd)
}
},
beforeDestroy () {
this.client && this.client.unpublish(this.localStream);
this.localStream && this.localStream.close();
this.client &&
this.client.leave(
() => {
console.log("Client succeed to leave.");
},
() => {
console.log("Client failed to leave.");
}
);
}
I have installed agora-rtc-sdk from npm.
My plugins/agora.js file looks like this
import Vue from "vue";
import AgoraRTC from 'agora-rtc-sdk';
Vue.use(AgoraRTC);
My nuxt.config.js has plugins declared as:
{
src: "~/plugins/agora.js",
ssr: false
}
The application on loading the page gives AgoraRTC is not defined. How do I add this AgoraRTC to my nuxt.js application?
Agora works only on the client side, fully independent of a server and hence you need to define the mode as client in the nuxt.config.js like this:
{ src: '~/plugins/agora.js', mode: 'client' },
im learning vue and setInterval doesn't work like in normal javascript? the problem is that my update function doesn't get fired.
start gets fired from a button, and hours/minutes/seconds are bound to input fields with v-model, i get all console.logs before the setInterval.
export default Vue.extend({
name: "timer-c",
data() {
return {
startDate: undefined,
hours: "",
minutes: "",
seconds: "",
timeLeft: undefined,
endDate: undefined,
interval: undefined,
text: "00:00:00",
sub: undefined,
};
},
methods: {
start: function() {
if (this.sub === undefined) {
let sum = 0;
if (this.seconds.match(/^\d+$/)) {
sum = sum + this.seconds * 1000;
console.log(sum);
}
if (this.minutes.match(/^\d+$/)) {
sum = sum + this.minutes * 60 * 1000;
}
if (this.hours.match(/^\d+$/)) {
sum = sum + this.hours * 60 * 60 * 1000;
}
if (sum === 0) {
console.log(this.$refs.br_start);
this.failed = true;
} else {
console.log(sum);
this.failed = false;
this.endDate = new Date(Date.now() + sum);
console.log(this.endDate);
this.startDate = new Date(Date.now());
console.log(this.startDate);
this.interval = setInterval(time => this.update, 1000);
//this.sub = this.interval.subscribe(time => this.update(time));
}
}
},
update: function() {
console.log('test');
const timeRemaining = Math.round((Date.now() - this.endDate) / 1000);
this.text = timeRemaining;
if (new Date(Date.now()) >= this.endDate) {
console.log("test");
}
},
Try to not return the function but execute it
this.interval = setInterval(time => { this.update(time) }, 1000);
I'd like to send base64 image as an attachment to a trello card through the API
POST /1/cards/[card id or shortlink]/attachments
There's a file field but it does not specify how should look the data there.
Refs: https://developers.trello.com/advanced-reference/card#post-1-cards-card-id-or-shortlink-attachments
Any idea?
Short answer: Trello's API only works to attach binary data via multipart/form-data. Examples below.
Long answer:
The Trello API to add attachments and images is frustratingly under-documented. They do have a coffeescript Client.js for those of us using Javascript to simplify all the basic operations: https://trello.com/1/client.coffee
Using the vanilla Client.js file I have been able to attach links and text files. While the CURL example shows pulling a binary file in from a hard drive, that doesn't work for those of us completely on a server or client where we don't have permissions to create a file.
From a LOT of trial and error, I've determined all binary data (images, documents, etc.) must be attached using multipart/form-data. Here is a jQuery snippet that will take a URL to an item, get it into memory, and then send it to Trello.
var opts = {'key': 'YOUR TRELLO KEY', 'token': 'YOUR TRELLO TOKEN'};
var xhr = new XMLHttpRequest();
xhr.open('get', params); // params is a URL to a file to grab
xhr.responseType = 'blob'; // Use blob to get the file's mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData(); // this is the formdata Trello needs
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
I have submitted a new coffeescript for Trello developer support to consider uploading to replace Client.js. It adds a "Trello.upload(url)" that does this work.
I've also attached here for convenience in JS form.
// Generated by CoffeeScript 1.12.4
(function() {
var opts={"version":1,"apiEndpoint":"https://api.trello.com","authEndpoint":"https://trello.com"};
var deferred, isFunction, isReady, ready, waitUntil, wrapper,
slice = [].slice;
wrapper = function(window, jQuery, opts) {
var $, Trello, apiEndpoint, authEndpoint, authorizeURL, baseURL, collection, fn, fn1, i, intentEndpoint, j, key, len, len1, localStorage, location, parseRestArgs, readStorage, ref, ref1, storagePrefix, token, type, version, writeStorage;
$ = jQuery;
key = opts.key, token = opts.token, apiEndpoint = opts.apiEndpoint, authEndpoint = opts.authEndpoint, intentEndpoint = opts.intentEndpoint, version = opts.version;
baseURL = apiEndpoint + "/" + version + "/";
location = window.location;
Trello = {
version: function() {
return version;
},
key: function() {
return key;
},
setKey: function(newKey) {
key = newKey;
},
token: function() {
return token;
},
setToken: function(newToken) {
token = newToken;
},
rest: function() {
var args, error, method, params, path, ref, success;
method = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
ref = parseRestArgs(args), path = ref[0], params = ref[1], success = ref[2], error = ref[3];
opts = {
url: "" + baseURL + path,
type: method,
data: {},
dataType: "json",
success: success,
error: error
};
if (!$.support.cors) {
opts.dataType = "jsonp";
if (method !== "GET") {
opts.type = "GET";
$.extend(opts.data, {
_method: method
});
}
}
if (key) {
opts.data.key = key;
}
if (token) {
opts.data.token = token;
}
if (params != null) {
$.extend(opts.data, params);
}
if (method === 'UPLOAD' && typeof (params) === "string" && params.length > 5) {
var xhr = new XMLHttpRequest();
xhr.open('get', params);
xhr.responseType = 'blob'; // Use blob to get the mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData();
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
} else {
return $.ajax(opts);
}
},
authorized: function() {
return token != null;
},
deauthorize: function() {
token = null;
writeStorage("token", token);
},
authorize: function(userOpts) {
var k, persistToken, ref, regexToken, scope, v;
opts = $.extend(true, {
type: "redirect",
persist: true,
interactive: true,
scope: {
read: true,
write: false,
account: false
},
expiration: "30days"
}, userOpts);
regexToken = /[&#]?token=([0-9a-f]{64})/;
persistToken = function() {
if (opts.persist && (token != null)) {
return writeStorage("token", token);
}
};
if (opts.persist) {
if (token == null) {
token = readStorage("token");
}
}
if (token == null) {
token = (ref = regexToken.exec(location.hash)) != null ? ref[1] : void 0;
}
if (this.authorized()) {
persistToken();
location.hash = location.hash.replace(regexToken, "");
return typeof opts.success === "function" ? opts.success() : void 0;
}
if (!opts.interactive) {
return typeof opts.error === "function" ? opts.error() : void 0;
}
scope = ((function() {
var ref1, results;
ref1 = opts.scope;
results = [];
for (k in ref1) {
v = ref1[k];
if (v) {
results.push(k);
}
}
return results;
})()).join(",");
switch (opts.type) {
case "popup":
(function() {
var authWindow, height, left, origin, receiveMessage, ref1, top, width;
waitUntil("authorized", (function(_this) {
return function(isAuthorized) {
if (isAuthorized) {
persistToken();
return typeof opts.success === "function" ? opts.success() : void 0;
} else {
return typeof opts.error === "function" ? opts.error() : void 0;
}
};
})(this));
width = 420;
height = 470;
left = window.screenX + (window.innerWidth - width) / 2;
top = window.screenY + (window.innerHeight - height) / 2;
origin = (ref1 = /^[a-z]+:\/\/[^\/]*/.exec(location)) != null ? ref1[0] : void 0;
authWindow = window.open(authorizeURL({
return_url: origin,
callback_method: "postMessage",
scope: scope,
expiration: opts.expiration,
name: opts.name
}), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
receiveMessage = function(event) {
var ref2;
if (event.origin !== authEndpoint || event.source !== authWindow) {
return;
}
if ((ref2 = event.source) != null) {
ref2.close();
}
if ((event.data != null) && /[0-9a-f]{64}/.test(event.data)) {
token = event.data;
} else {
token = null;
}
if (typeof window.removeEventListener === "function") {
window.removeEventListener("message", receiveMessage, false);
}
isReady("authorized", Trello.authorized());
};
return typeof window.addEventListener === "function" ? window.addEventListener("message", receiveMessage, false) : void 0;
})();
break;
default:
window.location = authorizeURL({
redirect_uri: location.href,
callback_method: "fragment",
scope: scope,
expiration: opts.expiration,
name: opts.name
});
}
},
addCard: function(options, next) {
var baseArgs, getCard;
baseArgs = {
mode: 'popup',
source: key || window.location.host
};
getCard = function(callback) {
var height, left, returnUrl, top, width;
returnUrl = function(e) {
var data;
window.removeEventListener('message', returnUrl);
try {
data = JSON.parse(e.data);
if (data.success) {
return callback(null, data.card);
} else {
return callback(new Error(data.error));
}
} catch (error1) {}
};
if (typeof window.addEventListener === "function") {
window.addEventListener('message', returnUrl, false);
}
width = 500;
height = 600;
left = window.screenX + (window.outerWidth - width) / 2;
top = window.screenY + (window.outerHeight - height) / 2;
return window.open(intentEndpoint + "/add-card?" + $.param($.extend(baseArgs, options)), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
};
if (next != null) {
return getCard(next);
} else if (window.Promise) {
return new Promise(function(resolve, reject) {
return getCard(function(err, card) {
if (err) {
return reject(err);
} else {
return resolve(card);
}
});
});
} else {
return getCard(function() {});
}
}
};
ref = ["GET", "PUT", "POST", "DELETE", "UPLOAD"];
fn = function(type) {
return Trello[type.toLowerCase()] = function() {
return this.rest.apply(this, [type].concat(slice.call(arguments)));
};
};
for (i = 0, len = ref.length; i < len; i++) {
type = ref[i];
fn(type);
}
Trello.del = Trello["delete"];
ref1 = ["actions", "cards", "checklists", "boards", "lists", "members", "organizations", "lists"];
fn1 = function(collection) {
return Trello[collection] = {
get: function(id, params, success, error) {
return Trello.get(collection + "/" + id, params, success, error);
}
};
};
for (j = 0, len1 = ref1.length; j < len1; j++) {
collection = ref1[j];
fn1(collection);
}
window.Trello = Trello;
authorizeURL = function(args) {
var baseArgs;
baseArgs = {
response_type: "token",
key: key
};
return authEndpoint + "/" + version + "/authorize?" + $.param($.extend(baseArgs, args));
};
parseRestArgs = function(arg) {
var error, params, path, success;
path = arg[0], params = arg[1], success = arg[2], error = arg[3];
if (isFunction(params)) {
error = success;
success = params;
params = {};
}
path = path.replace(/^\/*/, "");
return [path, params, success, error];
};
localStorage = window.localStorage;
if (localStorage != null) {
storagePrefix = "trello_";
readStorage = function(key) {
return localStorage[storagePrefix + key];
};
writeStorage = function(key, value) {
if (value === null) {
return delete localStorage[storagePrefix + key];
} else {
return localStorage[storagePrefix + key] = value;
}
};
} else {
readStorage = writeStorage = function() {};
}
};
deferred = {};
ready = {};
waitUntil = function(name, fx) {
if (ready[name] != null) {
return fx(ready[name]);
} else {
return (deferred[name] != null ? deferred[name] : deferred[name] = []).push(fx);
}
};
isReady = function(name, value) {
var fx, fxs, i, len;
ready[name] = value;
if (deferred[name]) {
fxs = deferred[name];
delete deferred[name];
for (i = 0, len = fxs.length; i < len; i++) {
fx = fxs[i];
fx(value);
}
}
};
isFunction = function(val) {
return typeof val === "function";
};
wrapper(window, jQuery, opts);
}).call(this);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>
On my cardboard app trying to show total of all features actual points for each column(Release) on the header, but that is not getting displayed.
See the image below the cards are my portfolioitem/feature, in particular release.
On each header with release information, below progress-bar I want to show total of all features actual points in that release.
Below is the code for that, I am not getting why actual_points are not getting displayed. I am doing something wrong, but I don't know where exactly it is
Ext.override(Rally.ui.cardboard.CardBoard,{
_buildColumnsFromModel: function() {
var me = this;
var model = this.models[0];
if (model) {
if ( this.attribute === "Release" ) {
var retrievedColumns = [];
retrievedColumns.push({
value: null,
columnHeaderConfig: {
headerTpl: "{name}",
headerData: {
name: "Backlog"
}
}
});
this._getLocalReleases(retrievedColumns, this.globalVar);
}
}
},
_getLocalReleases: function(retrievedColumns, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
var iteration_names = [];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
context: { projectScopeUp: false, projectScopeDown: false },
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
//limit: Infinity,
pageSize: 4,
//buffered: true,
//purgePageCount: 4,
fetch: ['Name','ReleaseStartDate','ReleaseDate','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
console.log("records values", records);
var start_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseStartDate'));
var end_date = Rally.util.DateTime.formatWithNoYearWithDefault(record.get('ReleaseDate'));
//this._getMileStones(record.get('ReleaseStartDate'), record.get('ReleaseDate'), this.project);
iteration_names.push(record.get('Name'));
//iteration_names.push(record.get('ReleaseDate'));
retrievedColumns.push({
value: record,
_planned_velocity: 0,
_actual_points: 0,
_missing_estimate: false,
columnHeaderConfig: {
headerTpl: "{name}<br/>{start_date} - {end_date}",
headerData: {
name: record.get('Name'),
start_date: start_date,
end_date: end_date,
planned_velocity: 0,
actual_points: 0,
missing_estimate: false
}
}
});
});
this._getAllReleases(retrievedColumns,iteration_names);
},
scope: this
}
});
},
_getAllReleases: function(retrievedColumns,iteration_names, today_iso) {
var me = this;
if (today_iso == undefined) {
today_iso = Rally.util.DateTime.toIsoString(new Date(),false);
}
var filters = [{property:'ReleaseDate',operator:'>',value:today_iso}];
Ext.create('Rally.data.WsapiDataStore',{
model:me.attribute,
autoLoad: true,
filters: filters,
sorters: [
{
property: 'ReleaseDate',
direction: 'ASC'
}
],
fetch: ['Name','Project','PlannedVelocity'],
listeners: {
load: function(store,records) {
Ext.Array.each(records, function(record){
var planned_velocity = record.get('PlannedVelocity') || 0;
var actual_points = record.get('LeafStoryPlanEstimateTotal') || 0;
var index = Ext.Array.indexOf(iteration_names[0],record.get('Name'));
if (planned_velocity == 0 ) {
retrievedColumns[index+1]._missing_estimate = true;
}
retrievedColumns[index+1]._actual_points += actual_points;
retrievedColumns[index+1]._planned_velocity += planned_velocity;
});
this.fireEvent('columnsretrieved',this,retrievedColumns);
this.columnDefinitions = [];
_.map(retrievedColumns,this.addColumn,this);
this._renderColumns();
},
scope: this
}
});
}
});
Ext.define('Rally.technicalservices.plugin.ColumnHeaderUpdater', {
alias: 'plugin.tscolumnheaderupdater',
extend: 'Ext.AbstractPlugin',
config: {
/**
*
* #type {String} The name of the field holding the card's estimate
*
* Defaults to c_FeatureEstimate (try LeafStoryPlanEstimateTotal)
*/
field_to_aggregate: "planned_velocity",
/**
* #property {Number} The current count of feature estimates
*/
total_feature_estimate: 0,
fieldToDisplay: "actual_points",
/**
* #property {String|Ext.XTemplate} the header template to use
*/
headerTpl: new Rally.technicalservices.template.LabeledProgressBarTemplate({
fieldLabel: 'Features Planned vs Planned Velocity: ',
calculateColorFn: function(data) {
if ( data.percentDone > 0.9 ) {
return '#EDB5B1';
}
return '#99CCFF';
},
showDangerNotificationFn: function(data) {
return data.missing_estimate;
},
generateLabelTextFn: function(data) {
if ( data.percentDone === -1 ) {
return "No Planned Velocity";
} else {
var text_string = "";
if ( data.field_to_aggregate === "planned_velocity" ) {
text_string = this.calculatePercent(data) + '%';
} else {
text_string = 'By Story: ' + this.calculatePercent(data) + '%';
}
return text_string;
}
}
})
//headerTpl: '<div class="wipLimit">({total_feature_estimate} of {planned_velocity})</div>'
},
constructor: function(config) {
this.callParent(arguments);
if(Ext.isString(this.headerTpl)) {
this.headerTpl = Ext.create('Ext.XTemplate', this.headerTpl);
}
},
init: function(column) {
this.column = column;
if ( column.value === null ) {
this.headerTpl = new Ext.XTemplate('');
}
this.planned_velocity = this.column._planned_velocity;
this.missing_estimate = this.column._missing_estimate;
this.actual_points = this.column._actual_points;
this.column.on('addcard', this.recalculate, this);
this.column.on('removecard', this.recalculate, this);
this.column.on('storeload', this.recalculate, this);
this.column.on('afterrender', this._afterRender, this);
this.column.on('ready', this.recalculate, this);
this.column.on('datachanged', this.recalculate, this);
},
destroy: function() {
if(this.column) {
delete this.column;
}
},
_afterRender: function() {
if ( this.feature_estimate_container ) {
this.feature_estimate_container.getEl().on('click', this._showPopover, this);
}
},
recalculate: function() {
this.total_feature_estimate = this.getTotalFeatureEstimate();
this.refresh();
},
refresh: function() {
var me = this;
if (this.feature_estimate_container) {
this.feature_estimate_container.update(this.headerTpl.apply(this.getHeaderData()));
} else {
this.feature_estimate_container = Ext.widget({
xtype: 'container',
html: this.headerTpl.apply(this.getHeaderData())
});
this.column.getColumnHeader().getHeaderTitle().add(this.feature_estimate_container);
}
if ( this.feature_estimate_container && this.feature_estimate_container.getEl()) {
this.feature_estimate_container.getEl().on('click', this._showPopover, this);
}
},
_showPopover: function() {
var me = this;
if ( me.planned_velocity > 0 ) {
if ( this.popover ) { this.popover.destroy(); }
this.popover = Ext.create('Rally.ui.popover.Popover',{
target: me.column.getColumnHeader().getHeaderTitle().getEl(),
items: [ me.getSummaryGrid() ]
});
this.popover.show();
}
},
getSummaryGrid: function() {
var me = this;
var estimate_title = "Feature Estimates";
if ( this.field_to_aggregate !== "c_FeatureEstimate") {
estimate_title = "Story Estimates";
}
var store = Ext.create('Rally.data.custom.Store',{
data: [
{
'PlannedVelocity': me.planned_velocity,
'ActualPoints': me.actual_points,
'TotalEstimate': me.getTotalFeatureEstimate(),
'Remaining': me.getCapacity(),
'MissingEstimate': me.missing_estimate
}
]
});
var grid = Ext.create('Rally.ui.grid.Grid',{
store: store,
columnCfgs: [
{ text: 'Plan', dataIndex:'PlannedVelocity' },
{ text: estimate_title, dataIndex: 'TotalEstimate' },
{ text: 'Remaining', dataIndex: 'Remaining' },
{ text: 'Team Missing Plan?', dataIndex: 'MissingEstimate' }
],
showPagingToolbar: false
});
return grid;
},
getHeaderData: function() {
var total_feature_estimate = this.getTotalFeatureEstimate();
actual_points = 0;
var percent_done = -1;
planned_velocity = 20;
if ( planned_velocity > 0 ) {
percent_done = total_feature_estimate / 4;
}
return {
actual_points: actual_points,
total_feature_estimate: total_feature_estimate,
planned_velocity: planned_velocity,
percentDone: percent_done,
field_to_aggregate: this.field_to_aggregate,
missing_estimate: this.missing_estimate
};
},
getCapacity: function() {
return this.planned_velocity - this.getTotalFeatureEstimate();
},
getTotalFeatureEstimate: function() {
var me = this;
var total = 0;
var total_unaligned = 0;
var records = this.column.getRecords();
Ext.Array.each(records, function(record){
var total_points = record.get('AcceptedLeafStoryPlanEstimateTotal');
var feature_estimate = record.get(me.field_to_aggregate) || 0;
var unaligned_estimate = record.get('UnalignedStoriesPlanEstimateTotal') || 0;
total += parseFloat(total_points,10);
});
if ( me.field_to_aggregate !== "planned_velocity" ) {
total = total
}
return total;
}
});