【问题标题】:Creating a button that requires input from functions in Javascript创建一个需要从 Javascript 中的函数输入的按钮
【发布时间】:2020-10-21 04:13:53
【问题描述】:

我有一个内置到 Weebly 网站的自定义 HTML 部分和一个 JavaScript 代码正在从中搜索和绘制各种数据的数据库。我已经设法设置函数来获取数据并绘制它并调用一个函数来创建下载。 HTML 然后尝试创建一个按钮来调用该函数。我无法实现的部分是将变量从 JavaScript 函数获取到 HTML 按钮。当页面呈现时,它会下载文件(由于 JavaScript 调用该函数)。当按钮被按下时,没有任何反应,控制台记录一个错误(因为参数不是从函数传递的。

最终的问题是:有没有办法 a) 在 JavaScript 函数中创建一个按钮 b) 全局保存变量并在 HTML 部分中创建按钮。我在下面发布了一般代码。非常感谢任何帮助!

编辑:我已经编辑了代码以显示整个代码,并且还尝试实现 Camilos 使用事件侦听器和 createElement 函数的想法。

<head>
<title>Chart Experimentation</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.js"> 
</script>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.16.min.js"></script>
</head>
<body>
// Sets up the canvas' for plots later on
<div class="chart-container">
<canvas id="myChart1"></canvas>
<canvas id="myChart2"></canvas>
</div>
<script>
// configures the tables that are going to be read through aws (you can 
ignore this)
AWS.config.update({
region: "My Region",
accessKeyId: "Key",
secretAccessKey: "Secret Key"  
});
var docClient = new AWS.DynamoDB.DocumentClient();
var table;
var tableName = "SkrootSensorTables";
function func1(sensorID, date, chartID) {
    var params = {
        TableName : tableName,
        KeyConditionExpression: "SensorID = :sid and #tim = :dat",
        ExpressionAttributeNames:{
            "#tim": "Timestamp"
        },
        ExpressionAttributeValues: {
            ":sid" : sensorID,
            ":dat" : date
        }
    };

    docClient.query(params, function(err, data) {
        if (err) {
            console.log(JSON.stringify(err, undefined, 2));
        } else {
            //console.log(JSON.stringify(data, undefined, 2));
            console.log(data);        
            chart(data, chartID);
        }
    });
}
// This is an intermediate step, you can ignore this
function chart(data, chartID) {
    table = data;
    try {
        tableName = table["Items"][0]["TableName"];
        sensorID = table["Items"][0]["SensorID"];
        queryAndChartData(tableName, sensorID, chartID);
    }
    catch (err) {
        console.log('Finally')
        throw "Exit Error";
    }
}
// This is an intermediate step in finding the data that will be charted (you 
can ignore this)
function queryAndChartData(tableName, sensorID, chartID) {
    console.log(tableName, sensorID, chartID);

    var params = {
        TableName : tableName
    };
    // This reads the data and finds the values that will be plotted
    docClient.scan(params, function(err, data) {
        if (err) {
            console.log(JSON.stringify(err, undefined, 2));
        } else {
            console.log(JSON.stringify(data, undefined, 2));

        // refine the data to chart it
        times = [];
        for (var i = 0; i < data["Items"].length; i++) {
            var t = data["Items"][i]["Timestamp"];
            times.push(t);
            console.log(t);
            }

            readings = [];
            for (var i = 0; i < data["Items"].length; i++) {
                var r = data["Items"][i]["Reading"];
                readings.push(r);
                console.log(r);
            }
            var ctx1 = document.getElementById(chartID).getContext('2d');
            var myChar1 = new Chart(ctx1, {
                type: 'line',
                data: {
                    labels: times,
                    datasets: [{
                        label: "Sensor ID: " + sensorID,
                        data: readings,
                        backgroundColor: 'rgba(0, 200, 255, 0.2)',
                        borderColor: 'rgba(0, 200, 255, 1)',
                        borderWidth: 1
                    }]
                }
            });
            // This is where I am trying to implement Camilos response
            const button = document.createElement('button');
            button.addEventListener('click', function auxfunc() {
                download_csv(times, readings);
            });
        }
    });
}
    function download_csv(time,readings) {
    var csv = 'Time,Reading\n';
    var data = [];
    for(let i = 0; i < readings.length; i++){
    data.push([time[i], readings[i]])
    console.log(datas)
    }
    data.forEach(function(row) {
        csv += row.join(',');
        csv += "\n";
    });

    console.log(csv);
    var hiddenElement = document.createElement('a');
    hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
    hiddenElement.target = '_blank';
    hiddenElement.download = 'SensorData.csv';
    hiddenElement.click();
}

// Creates plots for each day of the month (I realize there are better ways to record time)
// a) Ideally creates a download button below each plot (I haven't been able to figure this out)
var j = 1
for (var i = 6012020; i <= 6302020; i += 10000) {
    var Time = i
    var ChartName = "myChart" + j
    try {
        func1("33B178", Time, ChartName);
    setTimeout(() => {j++}, 2000);
    console.log(j)
    }
    catch(err) {
        document.getElementById("demo").innerHTML = err.message;
    }
}
</script>
// b) Ideally this would be able to receive the ouput of the function to use as imputs for the 
// download_csv function (it would also require a loop to create it for each plot.)
// <button onclick="download_csv()">Download CSV</button> 
</body>
</html>

【问题讨论】:

    标签: javascript html function button return


    【解决方案1】:

    为了给每个绘图添加一个按钮,您可以使用createElement 方法在您的javascript 代码中创建一个新按钮。它看起来像这样:

    const button = document.createElement('button');
    

    然后您可以使用addEventListener 方法指定单击时将调用哪个函数。它看起来像这样:

    button.addEventListener('click', download_csv);
    

    最后,您必须在循环中运行它,以便创建多个按钮,并确保将它们插入到各自的图表之后。我不熟悉weebly,所以我不确定它是如何创建图表的,但是您可以通过使用document.getElementById 之类的东西获取图表节点来在图表之后添加按钮,如果图表每个都有一个ID,然后使用appendChild 插入它。如果您将完整的 html 代码添加到您的问题中,我可能会给出更具体的内容

    因此,在您这样做之后,您应该在每个图表之后都有一个按钮,但是当您单击任何一个按钮时,它不会传递时间和读数参数。为此,您有两个选择,您可以使用bind 方法创建一个新函数,其中已指定参数,如下所示:

    button.addEventListener('click', download_csv.bind(this, times, readings));
    

    不要太担心this 参数。

    或者您可以改为传递一个调用 download_csv 函数的函数,并使用所需的参数,如下所示:

    button.addEventListener('click', function auxFunc() {
        download_csv(times, readings);
    });
    

    添加后,他们应该能够下载 csv。

    通过查看您的代码,我假设您希望将我解释过的所有代码放入 func1 函数中(如果您将其放入 func1 中,那么您无需在一个循环,因为 func1 函数已经在循环内被调用)。如果您不希望它在打开页面后立即下载 csv,请删除 func1 末尾的 download_csv(times, readings);

    编辑 1

    据我所知,按钮没有显示是因为您没有将它们插入到 DOM 树中。如果我正确理解您的代码,并且您想在每个画布之后插入按钮,那么您必须执行以下操作:

    const chartElement = document.getElementById(chartID);
    const button = document.createElement('button');
    button.addEventListener('click', function auxfunc() {
        download_csv(times, readings);
    });
    chartElement.parentNode.insertBefore(button, chartElement.nextSibling);
    

    这样按钮将被插入到画布之后。

    【讨论】:

    • 我相信这正是我想要的,感谢您的快速回复!我继续尝试进行您建议的编辑,但该按钮当前未出现。我已经发布了完整的代码供您查看,在此先感谢!
    • @CameronGreenwalt 检查我的编辑,基本上你必须将按钮插入到 DOM 树中
    • 是的,这正是我现在想要的!该按钮出现在情节下方,并为每个人创建一个下载按钮,非常感谢,这将花费我很长时间才能弄清楚!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    • 1970-01-01
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 2016-10-27
    • 1970-01-01
    相关资源
    最近更新 更多