我剛剛完成我預期的結果。基於@SiMag的評論,我發佈了包含幾個可能解決方案的答案。這篇文章分爲幾個部分,讓你瞭解我做錯了什麼,以及我做了什麼來解決這個問題。
我做錯了什麼?
由於@SiMag寫道:
沒有更新,腳本標籤先裝後使#{visualizationController.getData ...}表達式不再被評估,它們指的是老數據。
究竟是我的問題嗎?
此刻,當我知道我做錯了什麼,正確的問題是:
- 如何從CDI bean來的JavaScript傳遞多個值?
- 如何在服務器或客戶端調用javascript函數(將準備好的和所需的數據傳遞給此函數)?
應該如何在我的網頁作品?
這是一個你要知道答案,明白我將在接下來的章節中做的最後一個問題。我的頁面應該像這樣工作:
- 當頁面加載/打開,JavaScript函數應(自動無任何按下按鈕或鏈接)執行和功能應該使用哪一個我設置幾個值
createChart
CDI bean。作爲這一行動的結果,圖表應該出現。
- 每個當我按下該按鈕時,javascript函數應該被執行,並且功能應該使用哪個我在CDI豆設置幾個值
changeData
。作爲此操作的結果,圖表應更新其顯示的數據。
如果你想實現不同的東西,這是沒有問題的。基於你可以在這裏找到的解決方案,你將能夠實現你想要的。
首先溶液
第一解決方案是基於:
- 由
RequestContext
的手段傳遞一些值從CDI豆給javascript。爲了實現這一點,我基於documentation(第11.1節RequestContext);
- 調用服務器端的
createChart
功能;
- 在客戶端調用
changeChart
函數。
首先我添加了三個參數給我的JavaScript函數(每個值我想傳遞給來自CDI bean的JavaScript代碼)。目前,腳本應如下所示:
<script type="text/javascript">
//<![CDATA[
var chart;
var protos;
var dataChart;
var color;
var seriesChart;
var i, len;
//Creating the chart.
function createChart(protosArg, dataArg, colorsArg) {
$(function() {
//The data are parsed
protos = JSON.parse(protosArg);
dataChart = eval(dataArg);
colors = JSON.parse(colorsArg);
seriesChart = [];
//Creating several series of the data
for (i = 0, len = protos.length; i < len; i++) {
seriesChart.push({
color: color[i],
name: protos[i],
data: dataChart[i]
//other options
});
}
console.time('scatter');
console.time('asyncRender');
Highcharts.setOptions({
lang: {
//translate
}
});
// Create the chart
chart = new Highcharts.Chart({
//other options
chart: {
//other options
renderTo: "container"
},
series : seriesChart
});
console.timeEnd('scatter');
});
}
//Updating the chart using the new supplied data.
function changeData(protosArg, dataArg, colorsArg){
$(function() {
protos = JSON.parse(protosArg);
dataChart = eval(dataArg);
colors = JSON.parse(colorsArg);
seriesChart = [];
//Creating several series of the data using the new supplied data.
for (i = 0, len = protos.length; i < len; i++) {
seriesChart.push({
color: color[i],
name: protos[i],
data: dataChart[i]
//other options
});
}
//Removing the old data from the chart.
for (i = 0, len = chart.series.length; i < len; i++) {
chart.series[0].remove(false);
}
//Inserting the new data to the chart.
for (i = 0, len = protos.length; i < len; i++) {
chart.addSeries(seriesChart[i],false);
}
chart.redraw();
});
}
//]]>
</script>
讓我們繼續前進到服務器。在這裏我要告訴你,我的數據是怎樣的。在服務器端,我創建了三個String
變量。在服務器端這個變量的輸出是這樣的:
- PROTOS:
["tcp","udp",...]
- 數據:
[[[date,23],[date,1234]],[[date,1234]]]
- 顏色:
["black","white",...]
你上面怎麼看,我用它來JSON.parse()
和eval()
方法保存傳遞的數據。爲什麼?由於傳遞的數據被瀏覽器解釋爲字符串,所以我們必須將數據轉換爲數組。
在服務器端,我也使用RequestContext#addCallbackParam()
方法創建了幾個回調參數。 getProtos()
,getData()
和getColors()
方法返回字符串與我準備好的數據。
requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("protosArg", getProtos());
requestContext.addCallbackParam("dataArg", getData());
requestContext.addCallbackParam("colorsArg", getColors());
最後,我呼籲RequestContext#execute()
方法,它調用了createChart
javascript函數並傳遞三個必需的值:
@PostConstruct
public void init() {
//Creating the callback parameters.
initData();
requestContext.execute(String.format("createChart('%s', '%s', '%s')", getProtos(),getData(),getColors()));
}
注意,我用''
字符來實現對正確表示javascript方面。目前,數據將被瀏覽器解釋爲字符串。我呼籲在init()
方法方法(具有@PostConstruct
註解)的CDI bean的,所以我敢肯定:
- javascript函數將在最開始只執行一次
createChart
(對CDI bean有@ViewScoped
註釋);
- 將在腳本中下載的數據已準備就緒。
我已經在客戶端做的最後一件事是:改變<p:commandButton>
組件的oncomplete
屬性的值。 oncomplete
屬性調用changeData
javascript函數。 args
參數指的是我在服務器端設置的回調參數。我的CDI bean的
<p:commandButton id="filterButton" value="Filter" action="#{chart2Controller.actionFilterButton()}"
disabled="#{!chart2Controller.visibilityFilterButton}"
update="filterForm"
oncomplete="changeData(args.protosArg, args.dataArg, args.colorsArg);"/>
部分:
第二個解決方案是基於
@Named
@ViewScoped
public class Chart2Controller implements Serializable {
/**
* Start method.
*/
@PostConstruct
public void init() {
//Creating the callback parameters.
initData();
requestContext.execute(String.format("createChart('%s', '%s', '%s')", getProtos(),getData(),getColors()));
}
/**
* Downloading the data from the database.
*/
private void initData(){
/*
* Sending the query to the database including the filter options of the form,
* saving the result and preparing the data basing on the result.
*/
//Preparing the callback parameters.
requestContext = RequestContext.getCurrentInstance();
requestContext.addCallbackParam("protos", protos);
requestContext.addCallbackParam("data", data);
requestContext.addCallbackParam("colors", colors);
}
/**
* Action for the filter button.
*/
public void actionFilterButton(){
initData();
}
/**
* Visibility for filter button.
*/
public boolean getVisibilityFilterButton(){
//return true or false.
}
//Getter and Setter
private static final long serialVersionUID = -8128862377479499815L;
@Inject
private VisualizationService visualizationService;
private RequestContext requestContext;
private List<String> kindOfNetwork;
private List<String> selectedKindOfNetwork;
private String protos;
private String data;
private String colors;
}
解決方法二:
- 傳遞一些值從CDI bean來javascript通過
RequestContext
;
- 在客戶端調用
createChart
函數;
- 在客戶端調用
changeChart
函數。
您如何看到,此解決方案與以前的解決方案類似,但它的createChart
函數調用的地方不同。在這種情況下,我在客戶端調用了createChart
,並且我使用EL來提供來自CDI bean的值。
我不會重複代碼,所以我只會告訴你我做了什麼來實現預期的結果。在服務器端,除了調用RequestContext#execute()
方法之外,我已經完成了與之前解決方案相同的操作。相反,我在腳本末尾的客戶端調用了createChart
函數。這個腳本應該是這樣的:
<script type="text/javascript">
//<![CDATA[
var protos;
var dataChart;
var color;
//other code
//Creating the chart.
function createChart(protosArg, dataArg, colorsArg) {
$(function() {
protos = protosArg;
dataChart = dataArg;
colors = colorsArg;
//other code
});
}
//Updating the chart using the new supplied data.
function changeData(protosArg, dataArg, colorsArg){
$(function() {
//The data are parsed
protos = JSON.parse(protosArg);
dataChart = eval(dataArg);
colors = JSON.parse(colorsArg);
//other code
});
}
createChart(#{chart2Controller.protos}, #{chart2Controller.data}, #{chart2Controller.colors});
//]]>
</script>
注意,我也刪除了從createChart
功能JSON.parse()
和eval()
方法,因爲埃爾斯已經直接寫入JavaScript代碼和瀏覽器中正確解釋數據作爲陣列。
第三溶液
第三種解決方案是基於:
- 由
<h:inputHidden>
其它的組件來使從CDI豆給javascript一些值;
- 在客戶端調用
createChart
函數;
- 在客戶端調用
changeChart
函數。
這種解決方案是完全不同的。在開始時,我向表單中添加了三個<h:inputHidden>
組件(每個值都是我想要傳遞給javascript的一個值)。該形式應該是這樣的:
<h:form id="filterForm">
<h:inputHidden id="protos" value="#{chart2Controller.protos}" />
<h:inputHidden id="data" value="#{chart2Controller.data}" />
<h:inputHidden id="colors" value="#{chart2Controller.colors}" />
<p:selectManyCheckbox id="filter" value="#{chart2Controller.selectedKindOfNetwork}" layout="responsive" columns="4">
<p:ajax update="filterButton" />
<f:selectItems value="#{chart2Controller.kindOfNetwork}" var="kindOfNetwork" itemLabel="#{kindOfNetwork}" itemValue="#{kindOfNetwork}" />
</p:selectManyCheckbox>
<br/>
<p:commandButton id="filterButton" value="Filtruj" action="#{chart2Controller.actionFilterButton()}"
disabled="#{!chart2Controller.visibilityFilterButton}"
update="filterForm"
oncomplete="changeData();"/>
</h:form>
你上面怎麼看,我已經添加了<h:inputHidden>
的id
和value
屬性,我已經保存在value
屬性所需的數據。
注意,當你按下按鈕,形式更新(看update
屬性<p:commandButton>
成分的),所以我敢肯定,在輸入的value
屬性的數據將被下載每當我按下按鈕時。
最後,我通過document.getElementById("filterForm:idOfInput").value
的方式在JavaScript代碼中提到了這些值。請記住使用JSON.parse()
或eval()
,因爲數據被解釋爲字符串。該腳本應該是這樣的:
<script type="text/javascript">
//<![CDATA[
var chart;
var protos;
var dataChart;
var colors;
function createChart() {
$(function() {
protos = JSON.parse(document.getElementById("filterForm:protos").value);
dataChart = eval(document.getElementById("filterForm:data").value);
colors = JSON.parse(document.getElementById("filterForm:colors").value);
//other code
});
}
function changeData(){
$(function() {
protos = JSON.parse(document.getElementById("filterForm:protos").value);
dataChart = eval(document.getElementById("filterForm:data").value);
colors = JSON.parse(document.getElementById("filterForm:colors").value);
//other code
});
}
//]]>
</script>
Highcharts和更改圖表的數據
在我來說,我不知道有多少一系列數據中每個後,我會得到怎樣按下按鈕,所以我可以每次得到不同數量的系列。 Highcharts API不支持這種情況。您可以在循環中使用Chart.addSeries(),Series.setData()和Series.remove()方法的組合。如果我有更多時間,我會這樣做,我會更新這個答案。下面你可以找到一些重新創建/更新圖表的方法。
如果您不知道數據系列的數量。
首先解決
如果你不知道有多少一系列數據,你會得到(如在我的情況),你可以使用Series.remove()消除當前的一系列數據,然後添加新的系列數據通過Chart.addSeries()方式:
function changeData(...){
//Preparation of the received data.
//Removing the old data from the chart.
for (i = 0, len = chart.series.length; i < len; i++) {
chart.series[0].remove(false);
}
//Inserting the new data to the chart.
for (i = 0, len = protos.length; i < len; i++) {
chart.addSeries(seriesChart[i],false);
}
chart.redraw();
}
注意,我已經設置false
爲redraw
參數由於有效。 Highcharts API說:
如果在圖表上做了更多的操作,最好將重繪設置爲false並在之後調用chart.redraw()。
解決方法二
您也可以摧毀圖表並重新創建它。在這種情況下,你已經也改變changeData
javascript函數如下:
function changeData(...){
chart.destroy();
createChart(...);
}
如果你知道該系列中的數據的數量。
這種情況比以前更容易。看看下面的代碼,它不需要任何解釋:
function changeData(...){
//Preparation of the received data.
for(var i = 0; i < chart.series.length; i++){
chart.series[i].setData(seriesData[i],false);
}
chart.redraw();
}
腳本標記,以便語句#{visualizationController ...}不再被評估不先裝後更新,他們指的是舊數據。您可以在表單中使用三個h:inputHidden來存儲您需要在JavaScript中訪問的數據,並且將createChart函數 – SiMag
中的這些輸入值作爲前一篇文章的補充,我不確定是否創建新圖表在你的情況下,時間是最好的主意。難道你不能只使用Series.update()或者Series.setData()方法嗎? –
@SiMag,謝謝你的反饋。我試圖實現你的想法。我已經創建了三個'的部件(與'id'和'值= 「#{visualizationController.getData ...}」'屬性)在我'filterForm'形式。然後,我在我的'createChart'函數中引用了這些輸入的值,如下所示:'variable = document.getElementById(「filterForm:idInput」)。value;'。不幸的是,這是行不通的。目前,我的圖表根本沒有創建。它看起來像:Javascript代碼是在表單創建之前或數據下載之前執行的。可能嗎? –
Robert