I am trying to create a script with flask that increments or decrements a value by ten by clicking a button. I alraeady have a script that does this in the backend, but I am having trouble displaying and dynamically updating this value in the frontend. Basically, I want to change this value in the frontend and backend at the same time without refressing the page.
Here is the Backend Code (shortened to include the page in question):
app.py - The Flask App
from flask import Flask, render_template, url_for, request, jsonify
app = Flask(__name__)
#motor = Motor(17, 18)
def setBPM(current, change=0):
return ((current < 200) & (change > 0))*(current+change) + ((current > 30) & (change < 0))*(current+change)
#app.route('/pulse')
def pulse():
return render_template("pulse.html")
#app.route('/pulseUP', methods=['POST'])
def pulseUp():
BPM = setBPM(BPM, 10)
return (render_template('pulse.html', get_BPM_var=BPM))
#app.route('/pulseDOWN', methods=['POST'])
def pulseDwn():
BPM = setBPM(BPM, -10)
return (render_template('pulse.html', get_BPM_var=BPM))
#app.context_processor
def get_BPM_var():
return dict(get_BPM_var=BPM)
if __name__ == "__main__":
app.run(debug=True)
Frontend - pulse.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=800px, inital-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}"
</head>
<body>
<div class="parent">
<div class="child">
<div id="grid-pulse">
<div class="cell-pulse">
<form action="/pulseUP/" method="post"><input type="submit" value="+" /></form>
</div>
<div class="cell-pulse"></div>
<div class="cell-pulse">
<div class="numbkgnd">
<h3 id="BPMID">{{ get_BPM_var }}
BPM</h3>
</div>
</div>
<div class="cell-pulse"></div>
<div class="cell-pulse">
<form action="/pulseDOWN/" method="post"><input type="submit" value="-" /></form>
</div>
<div class="cell-pulse"></div>
</div>
</div>
</div>
<script>
$("#BPMID").keyup(function () {
var text = $(this).val();
$.ajax({
url: "/pulse",
type: "get",
data: { jsdata: text },
success: function (response) {
$("#BPMID").html(response);
},
error: function (xhr) {
}
});
});
</body>
</html>
I tried to use ajax to update the value, but I am not familair with javascript in the slightest. Any help would be greatly apprieciated!!
My example is based on a range slider whose value corresponds to the speed sent to the server. The value can be increased and decreased in increments of 10.
When a change event is triggered, the browser sends an AJAX POST type request to the server using the Fetch API. The request in JSON format contains the current value of the slider.
The server sets the received value as long as it is within the permitted range and replies in JSON format with the current speed.
After receiving the answer, the output in the browser is now adjusted, i.e. the value is output as text and set as the new value of the slider.
In addition to the slider, two buttons can also be used to set the value. Pressing it sets the slider's value and triggers its change event. After that, the process remains the same.
from flask import (
Flask,
jsonify,
render_template,
request
)
class Motor:
def __init__(self):
self._rpm = 30
#property
def rpm(self):
return self._rpm
#rpm.setter
def rpm(self, value):
if 30 <= value <= 200:
self._rpm = value
else:
raise ValueError('Value range must be between 30 and 200.')
app = Flask(__name__)
motor = Motor()
#app.route('/')
def index():
v = motor.rpm
return render_template('index.html', **locals())
#app.post('/adjust-speed')
def adjust_speed():
v = motor.rpm
try:
motor.rpm = int(request.get_json(force=True).get('v'))
v = motor.rpm
finally:
return jsonify(**locals())
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Control</title>
</head>
<body>
<input type="range" min="30" max="200" value="{{ v }}" step="10" id="speed">
<p>Velocity: <output id="value">{{ v }}</output></p>
<button id="btn-dec">-</button>
<button id="btn-acc">+</button>
<script type="text/javascript">
(() => {
/** Send the expected speed to the server. */
const adjustSpeed = async (value) => {
const data = await fetch('/adjust-speed', {
method: 'post',
body: JSON.stringify({ v: value })
}).then(resp => resp.ok && resp.json());
if (!data || !data.v) throw new Error('Error adjusting speed.');
return data.v;
};
const outputValue = document.getElementById('value');
const speedSlider = document.getElementById('speed');
speedSlider.addEventListener('change', async function() {
// Send the slider's value to the server and
// output the actual speed obtained.
try {
const v = await adjustSpeed(Number(this.value));
this.value = v;
outputValue.innerText = v;
} catch(err) {
console.error(err);
}
});
const buttonAcc = document.getElementById('btn-acc');
buttonAcc.addEventListener('click', () => {
// Set the new value of the slider and trigger the change event.
const value = Number(speedSlider.value), step = Number(speedSlider.step);
speedSlider.value = value + step;
speedSlider.dispatchEvent(new Event('change'));
});
const buttonDec = document.getElementById('btn-dec');
buttonDec.addEventListener('click', () => {
// Set the new value of the slider and trigger the change event.
const value = Number(speedSlider.value), step = Number(speedSlider.step);
speedSlider.value = value - step;
speedSlider.dispatchEvent(new Event('change'));
});
})();
</script>
</body>
</html>
If you don't like the control provided by the slider, you can also control the speed directly using the buttons. In this case, the following variant is possible.
#app.post('/accelerate')
def accelrate():
v = motor.rpm
try:
motor.rpm += int(request.get_json(force=True).get('a'))
v = motor.rpm
finally:
return jsonify(**locals())
const accelerate = async (value) => {
const data = await fetch('/accelerate', {
method: 'post',
body: JSON.stringify({ a: value })
}).then(resp => resp.ok && resp.json());
if (!data || !data.v) throw new Error('Error adjusting speed.');
return data.v;
};
const outputValue = document.getElementById('value');
const buttonAcc = document.getElementById('btn-acc');
buttonAcc.addEventListener('click', async () => {
try {
const v = await accelerate(10);
outputValue.innerText = v;
} catch(err) {
console.error(err);
}
});
const buttonDec = document.getElementById('btn-dec');
buttonDec.addEventListener('click', async () => {
try {
const v = await accelerate(-10);
outputValue.innerText = v;
} catch(err) {
console.error(err);
}
});
Related
I'm learning JS and I'm trying to create a web game with javascript. The goal is simple: a flag is displayed at random, and the player must guess the name of the country associated with the flag.
The flag is randomly selected and displayed correctly, but I have a problem with the user interaction. I'd like to display "bad answer" in a <p> and if it's correct, display "good answer" (in a <p>), regenerate a flag and start again, indefinitely. The problem is that I can get the user's answer but i can't compare it to real answer and then display true or false.
I would like to know if someone could explain to me what is wrong and correct me please. Here is my code :
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
function getVal() {
const inputValue = document.querySelector('input').value;
console.log(inputValue);
}
function getData() {
var json = 'https://cdn.jsdelivr.net/npm/country-flag-emoji-json#2.0.0/dist/index.json'
fetch(json)
.then(data => data.json())
.then(data => {
const randomInt = getRandomInt(data.length);
console.log(data[randomInt]);
var image = document.getElementById("flag");
image.src = data[randomInt].image;
});
if (inputValue != data[randomInt].name.toLowerCase()) {
document.getElementsByClassName('result').class.add("result-false");
document.getElementsByClassName('result').innerHTML = 'Mauvaise Réponse';
} else if (inputValue == data[randomInt].name.toLowerCase()) {
document.getElementsByClassName('result').class.add("result-true");
document.getElementsByClassName('result').innerHTML = 'Bonne Réponse';
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guess The Flag - </title>
<link rel="stylesheet" href="style.css">
<!-- <script type="text/js" src="app.js"></script> -->
</head>
<body>
<h1>GuessTheFlag</h1>
<div class="flagCanva">
<img id="flag" src="https://cdn.jsdelivr.net/npm/country-flag-emoji-json#2.0.0/dist/images/KH.svg" alt="">
</div>
<input type="text" name="flagName">
<button type="submit" onclick="getVal()">Je valide</button>
<p class="result"></p><br>
<button onclick="getData()">Next</button>
</body>
</html>
The reason is because the scope of inputValue is inside the function getVal only.
So in function getData it doesn't know inputValue.
The scope is the perimeter where the variable is known, it could be globally, local to a function, or at other level. It depends where and how you declare the variable.
It's an important thing to understand in most of the computer langage.
Here's a refactored working version with some comments to help clear things out:
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
let flag = "Cambodia"; // <= We need a global variable so that it can be set and accessed inside getVal() and getData()
function getVal() {
const inputValue = document.querySelector('input').value;
//>> Move the flag vs input comparison inside the input event handler:
if ( inputValue.toLowerCase() !== flag.toLowerCase()) { // <= Lowercasing both input and flag name to avoid case sensitive comparison failures
// Use `classList` instead of `class` to have access to the add() method
// Use `querySelector` to pick a single element instead of getElementsByClassName which returns a list of elements:
document.querySelector('.result').classList.add("result-false");
document.querySelector('.result').innerHTML = 'Mauvaise Réponse';
// No need for an else if here:
} else {
document.querySelector('.result').classList.add("result-true");
document.querySelector('.result').innerHTML = 'Bonne Réponse';
}
}
// TIP: Ideally the next function should be split into 2 functions:
// 1) fetchData(), runs once to grab the JSON
// 2) getRandomFlag(), runs on 'Next' click to get a random flag
// without re-fetching the JSON.
function getData() {
var json = 'https://cdn.jsdelivr.net/npm/country-flag-emoji-json#2.0.0/dist/index.json'
fetch(json)
.then(data=>data.json())
.then(data=> {
const randomInt = getRandomInt(data.length);
console.log(data[randomInt]);
var image = document.getElementById("flag");
image.src = data[randomInt].image;
flag = data[randomInt].name; // <= Set the value for the newly fetched flag name
});
}
Working demo:
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
let flag = "Cambodia"; // <= We need a global variable so that it can be set and accessed inside getVal() and getData()
function getVal() {
const inputValue = document.querySelector('input').value;
//>> Move the flag vs input comparison inside the input event handler:
if(inputValue.toLowerCase() != flag.toLowerCase()) {
// Use `classList` instead of `class` to have access to the add() method
// Use `querySelector` to pick a single element instead of getElementsByClassName which returns a list of elements:
document.querySelector('.result').classList.add("result-false");
document.querySelector('.result').innerHTML = 'Mauvaise Réponse';
} else {
document.querySelector('.result').classList.add("result-true");
document.querySelector('.result').innerHTML = 'Bonne Réponse';
}
}
function getData() {
var json = 'https://cdn.jsdelivr.net/npm/country-flag-emoji-json#2.0.0/dist/index.json'
fetch(json)
.then(data=>data.json())
.then(data=> {
const randomInt = getRandomInt(data.length);
console.log(data[randomInt]);
var image = document.getElementById("flag");
image.src = data[randomInt].image;
flag = data[randomInt].name;
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guess The Flag - </title>
<link rel="stylesheet" href="style.css">
<!-- <script type="text/js" src="app.js"></script> -->
</head>
<body>
<h1>GuessTheFlag</h1>
<div class="flagCanva">
<img width="100" id="flag" src="https://cdn.jsdelivr.net/npm/country-flag-emoji-json#2.0.0/dist/images/KH.svg" alt="">
</div>
<input type="text" name="flagName">
<button type="submit" onclick="getVal()">Je valide</button>
<p class="result"></p><br>
<button onclick="getData()">Next</button>
</body>
</html>
There's a lot of refactoring that we can do (e.g. caching the selected elements, cache the json response to avoid re-fetching the data, removing global variables, etc.) to improve the code, but this is just a good start for a functional code.
please am trying to integrate sending any trc20 token using tronlink by clicking a button on my website. I was able to send TRX using the JavaScript code below but I want to be able to send trc-20 like USDT, any help will be highly appreciated. Thanks
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>
<input type="text" name="numb" id="numb">
<button onclick="sendtron()">Can you get tronweb from tronlink?</button>
</div>
<script>
function sendtron(){
var obj = setInterval(async ()=>{
if (window.tronWeb && window.tronWeb.defaultAddress.base58) {
clearInterval(obj)
var tronweb = window.tronWeb
var amount = document.querySelector('#numb').value;
var tokens = amount * 1000000
var tx = await tronweb.trx.sendTransaction("TWs2Z7dLMcPnXi9pnWqCUPzAnqUv6T54dy", tokens)
var signedTx = await tronweb.trx.sign(tx)
var broastTx = await tronweb.trx.sendRawTransaction(signedTx)
console.log(broastTx);
}
});
}
</script>
</body>
</html>
TRC20 are actually smart contracts. tronscan USDT link To transfer TRC20 from your address to another address, you will be calling TRC20's transfer function, below is a snippet of Tron USDT's code.
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
TronWeb TRC20 Contract Interaction documentation. You can use tronWeb's triggerSmartContract function to create a raw transaction, sign and broadcast.
create raw transaction
var senderAddress = tronweb.defaultAddress.base58;
var receiverAddress = "TV3nb5HYFe2xBEmyb3ETe93UGkjAhWyzrs";
var amount = 100;
var parameter = [{type:'address',value:receiverAddress},{type:'uint256',value:amount}]
var options = {
feeLimit:100000000
}
const transactionObject = await tronWeb.transactionBuilder.triggerSmartContract(
tronweb.address.toHex(contractAddress),
"transfer(address,uint256)",
options,
parameter,
tronweb.address.toHex(senderAddress)
);
Note: address are all in base58 format, we need to convert it to hex format using tronweb.address.toHex(address) at transactionObject. The parameter variable is where we set the receiver address and amount.
Sign
var signedTransaction = await tronWeb.trx.sign(transactionObject.transaction);
Broadcast
var broadcastTransaction = await tronWeb.trx.sendRawTransaction(signedTransaction);
console.log(broadcastTransaction);
I am practicing creating a weather app and I want to fetch data using async await. But before that, I need to read the city name that user provides in search bar. In my current code, the async function tries to fetch data without the city being set in the query.
How can I handle this with best practices, such that this weather api call is made only after citname is retrieved?
Please find my code below:
'use strict';
(function() {
const inputEl = document.querySelector(".search-placholder");
let cityName = '';
const debounce = (func, wait, immediate) => {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const handleSearchText= debounce(function(e) {
cityName = e.target.value;
console.log(cityName);
inputEl.placeholder = cityName;
}, 250);
inputEl.addEventListener("keyup", handleSearchText);
// make request to openweatherapi & make api call
async function getWeatherdata(event) {
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url);
console.log(url)
return response.json();
event.preventDefault();
}
inputEl.addEventListener('submit', () => getWeatherdata());
})();
'use strict';
(function() {
const inputEl = document.querySelector(".search-placholder");
// Get the form element.
const formEl = document.querySelector('form.weatherdata-form');
let cityName = '';
const debounce = (func, wait, immediate) => {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const handleSearchText = debounce((e) => {
cityName = e.target.value;
inputEl.placeholder = cityName;
}, 250);
inputEl.addEventListener("keyup", handleSearchText);
// make request to openweatherapi & make api call
async function getWeatherdata(event) {
const form = event.target.form;
const formData = new FormData(form);
let cityName = formData.get('city-name');
console.log(cityName)
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url, {
method: 'POST',
body: formData
});
event.preventDefault();
return response.json();
}
const weatherDetails = formEl.addEventListener('submit', getWeatherdata);
console.log(weatherDetails)
})();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My cool weather app</title>
<link href="https://fonts.googleapis.com/css?family=Raleway&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="index.css">
</head>
<body>
<main>
<div class="search-container">
<div class="search-bar">
<form class="weatherdata-form">
<i class="fa fa-search fa-3x" id="icon"></i>
<input type="text" class="search-placholder" placeholder="Type city to find weather..." name="city-name"/>
<!-- <button type="submit">Submit</button> -->
</form>
</div>
</div>
</main>
<script src="index.js"></script>
</body>
</html>
Add your submit event listener to the form element instead of the button directly. This will give you the posibility to extract all the values of form elements from your form with the FormData API.
Make sure that your input fields have the name attribute as we will use this to get the values you need.
<form class="weatherdata-form">
<input class="search-placholder" type="text" name="city-name"/>
<button type="submit">Submit</button>
</form>
// Get the form element.
const formEl = document.querySelector('form.weatherdata-form');
Modify your getWeatherdata function to extract the target property of the current Event. This will give us information which form this is that has been submitted. This opens up the possibility to make this function applicable to other forms.
Create an instance of FormData with the form as argument to create an extraction of your inputs with their names and values. With the FormData.get() method you can pick a single value from the form by giving its name. Inject that value in to your URL string and you're done here.
Edit
The form constant came up undefined and should have been event.target; No form was found and so no values were found. I've also added a check that if cityName is an empty string it will stop the function and not call the fetch. Remove the if statement if you want to call fetch without conditions.
async function getWeatherdata(event) {
const form = event.target;
const formData = new FormData(form);
const cityName = formData.get('city-name');
if (cityName === '') return;
event.preventDefault();
const url = `http://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=2489ed561dc99d173a2f394574bc107e`;
const response = await fetch(url);
const json = await response.json();
console.log(json);
}
Add the event listener to the form element and set the listener callback directly to the getWeatherdata function. Now the form will submit the event and open up all the values of the form to use.
formEl.addEventListener('submit', getWeatherdata);
Hope this helps you out, friend. If this didn't solve your question or you have more questions, please let me know.
Cheers!
I am new to JS development. I found a nodejs calculator project on github that I've been manipulating.
My Problem: In my calculator, I'm trying to combine all of my results together. However, the data of my old entries are still present, I would like to remove these old entries and have it update instead with the most up-to-date entry.
I know it has something to do with data-ng-repeat (shown in my index code below), but I've tried other directives and they haven't worked. Is there something I need to change in my code to use a different directive?
Here's what I am working with, everything works well until the last screenshot:
Widget calculator
https://imgur.com/a/2ebpyym
Specific Widget Selection
https://imgur.com/a/STYeLcF
Entering QTY of Widgets
https://imgur.com/a/B5ii32J
Calculation Result #1 (1 Sheet is worth 8 Widgets)
https://imgur.com/a/CUouHAt
Problem: Calculation Result #2
https://imgur.com/a/XJrclUY
In the above link, I would prefer if the "62.5" in the "Combined Sheets Needed" section is replaced by "93.75"
Code
server.js
'use strict';
const express = require('express');
const app = express();
let PORT = process.env.PORT || 3000;
console.log('hello1')
let operators = [
{name:'24x24 Widget', symbol:'24x24 Widget'}
];
function calculate(operator, value1, value2) {
if ( operator == '24x24 Widget' ) return value1 /8 + " sheets";
}
app.use(express.static(__dirname + '/build'));
app.use(require('body-parser').json());
app.use((req, res, next) => {
// res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Origin', 'https://mean-calculator.herokuapp.com/calculator');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
next();
});
app.listen(PORT, () => {
console.log('server started on port', PORT);
});
var array = [];
app.route('/calculator')
.get((req, res) => {
res.json({
operators
});console.log('hello in route')
array = [];
})
.post((req, res) => {
let operator = req.body.operator.name;
let value1 = req.body.value1;
let result = calculate(operator, value1);
array.push(value1/8);
console.log(array);
var sum = array.reduce(function(a, b) { return a + b; }, 0);
console.log(sum, 'this is the sum');
let doubleresult = calculate(operator, value1*2)
res.json({
result: {
operator: req.body.operator.symbol,
value1,
result,
sum
}
});
});
index.html
(Check comment: <!-- Combining Data Here-->)
<!DOCTYPE html>
<html data-ng-app="App">
<head>
<meta charset="utf-8">
<link href='https://fonts.googleapis.com/css?family=Open+Sans|Lora|Lato:700' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="main.css" charset="utf-8">
<title>Widget Calculator</title>
</head>
<body data-ng-controller="AppController as appCtrl"></body>
<h1>Solve for Material Needed for Widgets</h1>
<div class="solve">
<h2 data-ng-show="appCtrl.error" class="error">{{appCtrl.error}}</h2>
<form method="post">
<h2>Select a Widget</h2>
<select data-ng-model="operator" data-ng-options="operatorOption.name for operatorOption in appCtrl.operators">
<option value="">-- choose Widget --</option>
</select>
<h2>Select QTY</h2>
<input data-ng-model="value1" type="number" placeholder="1st Number">
<span>{{operator.symbol}}</span>
<span></span>
<button data-ng-click="appCtrl.calculate(operator, value1, value2); value1=undefined; value2=undefined; operator=undefined" type="button">Calculate</button>
</form>
</div>
<div data-ng-show="appCtrl.results.length">
<h1>Results</h1>
<div class="result">
<h2 data-ng-repeat="result in appCtrl.results">{{result.value1}} {{result.operator}} = {{result.result}}</h2>
</div>
</div>
<!-- Combining Data Here-->
<div data-ng-show="appCtrl.results.length">
<h1>Combined Sheets Needed</h1>
<div class="result combined">
<h2 data-ng-repeat="result in appCtrl.results">{{result.sum}}</h2>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.6/angular.js" charset="utf-8"></script>
<script src="app.js" charset="utf-8"></script>
</body>
</html>
app.js
var app = angular.module('App', []);
app.controller('AppController', ['$http', function($http) {
var apiRoute = 'http://localhost:3000/calculator';
var _this = this;
_this.results = [];
_this.operators = [];
$http.get(apiRoute)
.then(function(res) {
_this.operators = res.data.operators;
}, function(res) {
console.log(res);
});
_this.calculate = function(operator, value1, value2) {
_this.error = validate(operator, value1, value2);
if (!_this.error) {
$http.post(apiRoute, {operator, value1, value2})
.then(function(res) {
_this.results.push(res.data.result);
}, function(res) {
console.log(res);
});
}
}
}]);
function validate(operator, value1, value2) {
if (!operator) return 'Please select an operator.';
if ((!value1 && value1 != 0) || (!value1 && value1 != 0)) return 'Please enter two numbers.';
return null;
}
I have been looking at the rally Object model, but I can't figure out how to grab the Name attribute of a Defect's Tag.
I made sure to include Tag and Tags in my fetch statement. I am storing all the defects into an array of objects called defectsNEWDEFECTS[]
I can return a Tag object by doing this:
tagNEWDEFECTS = defectsNEWDEFECTS[i].Tags;
document.write(tagNEWDEFECTS);
which will return this:
[object Object]
But, I can't seem to get it to return the NAME of the tag.
I tried:
tagNEWDEFECTS = defectsNEWDEFECTS[i].Tags.Name;
tagNEWDEFECTS = defectsNEWDEFECTS[i].Tags.Tag.Name;
tagNEWDEFECTS = defectsNEWDEFECTS[i].Tag.Name;
But they all return 'undefined'.
Any ideas how to get the name of a tag? Ultimately, the goal here is to have user-input custom tags that I can flag in my program to do certain things. For example, one tag will be named 'RollOverDefect'.
I need to be able to determine which Defects have a Tag called 'RollOverDefect'
Thanks!
Tags is a collection, so you'll ultimately need a nested loop over the Tags collection attribute to handle this. Once you've nested into an additional loop, you can reference the Tag Name via:
tagNEWDEFECTS = defectsNEWDEFECTS[i].Tags[j].Name;
Hope this is helpful - let us know if that gets the job done.
You may find this example to be useful:
<html>
<head>
<title>App Example: Defects with Tags</title>
<meta name="Name" content="App Example: Defects with Tags" />
<meta name="Version" content="2013.2" />
<meta name="Vendor" content="Rally Labs" />
<script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.43""></script>
<script type="text/javascript">
var table = null;
function defectsWithTagsExample() {
var rallyDataSource = new rally.sdk.data.RallyDataSource('__WORKSPACE_OID__',
'__PROJECT_OID__',
'__PROJECT_SCOPING_UP__',
'__PROJECT_SCOPING_DOWN__'
);
function itemQuery() {
var queryObject = {
key: 'defects',
type: 'Defect',
fetch: 'FormattedID,Name,State,Description,Tags,Name',
query: '(State = "Submitted")'
};
rallyDataSource.findAll(queryObject, populateTable);
}
function populateTable(results) {
if (table) {
table.destroy();
}
var tableDiv = document.getElementById('aDiv');
var config = {
'columnKeys' : ['FormattedID', 'Name', 'Description', 'State', 'Tags'],
'columnHeaders' : ['FormattedID', 'Name', 'Description', 'State', 'Tags'],
'columnWidths' : ['100px', '400px', '200px', '85px', '300px']
};
table = new rally.sdk.ui.Table(config);
table.addRows(results.defects);
for (i=0;i<results.defects.length;i++) {
myDefect = results.defects[i];
myTags = results.defects[i].Tags;
myTagString = "";
for (j=0;j<myTags.length;j++) {
myTag = myTags[j];
myTagName = myTags[j].Name;
if (j == 0) {
myTagString += myTagName;
} else {
myTagString += ", " + myTagName;
}
}
linkConfig = {item: {FormattedID: myDefect.FormattedID, "_ref" : myDefect._ref}};
defectLink = new rally.sdk.ui.basic.Link(linkConfig);
table.setCell(i, 0, defectLink.renderToHtml());
table.setCell(i, 4, myTagString);
}
table.display(tableDiv);
};
itemQuery();
}
rally.addOnLoad(defectsWithTagsExample);
</script>
</head>
<body>
<div id="aDiv"></div>
</body>
</html>