如何防止SAPUI5生命周期运行两次?

时间:2017-04-08 05:40:12

标签: rendering sap lifecycle sapui5

我有一个包含散点图的自定义控件。按下按钮时,它会打开一个显示图表的模态/对话框控件(参见下图)。唯一的问题是图表显示两次!打开开发工具后,似乎所有生命周期都会呈现两次。我不知道为什么会发生这种情况,但我需要只渲染一次

这是我的主控制器:

main.controller.js

jQuery.sap.registerModulePath("vizConcept.ScatterPlot", "controls/ScatterPlot");
jQuery.sap.require("vizConcept.ScatterPlot");
jQuery.sap.registerModulePath("vizConcept.ScatterPlotItem", "controls/ScatterPlot");
jQuery.sap.require("vizConcept.ScatterPlotItem");


sap.ui.define([
        'jquery.sap.global',
        'vizConcept/controller/BaseController',
        'sap/ui/model/json/JSONModel',
        'vizConcept/model/viewControls',
        'sap/m/Button',
        'sap/m/Dialog',
    ],

    function (jQuery, BaseController, JSONModel, viewControls, Button, Dialog) {

        "use strict";

        var controls;

        var mainController = BaseController.extend("vizConcept.controller.Main", {

            onInit: function(oEvent) {

                // Access/expose the defined model(s) configured in the Component.js or Manifest.json within the controller.
                this.getView().setModel(this.getOwnerComponent().getModel("products"), "products");
                var oModel = this.getView().getModel("products");
                this.getView().setModel(oModel);
                //
                console.log('onInit');
                var sUrl = "#" + this.getOwnerComponent().getRouter().getURL("page2");

        //IIFE renders our chart, will need to move this in a modular way        
            }, 

            onAfterRendering: function () {
                this._rebindAll();
            },

        _rebindAll : function() {

            var oModel = new sap.ui.model.json.JSONModel({
              "buckets": [
        {
            "quarter": "Q2 2013",
            "values": [
                 {  "name":     "Segment A",
                    "value":    "3228",
                    "value2":   "12"    
                 },
                 {
                    "name": "Segment B",
                    "value":    "11752",
                    "value2":   "37"
                 },
                 {
                    "name": "Segment C",
                    "value":    "492",
                    "value2":   "3"
                 },
                 {
                    "name": "Segment D",
                    "value":    "654",
                    "value2":   "6"
                 },
                 {
                    "name": "Segment E",
                    "value":    "39165",
                    "value2":   "167"
                 },
                 {
                    "name": "Segment F",
                    "value":    "4745",
                    "value2":   "9"
                 }
            ]   
        },
        {
            "quarter":  "Q3 2013",
            "values":   [
                {   "name":     "Segment A",
                    "value":    "6806",
                    "value2":   "24"
                 },
                 {
                    "name": "Segment B",
                    "value":    "11372",
                    "value2":   "51"
                 },
                 {
                    "name": "Segment C",
                    "value":    "2306",
                    "value2":   "10"
                 },
                 {
                    "name": "Segment D",
                    "value":    "1492",
                    "value2":   "7"
                 },
                 {
                    "name": "Segment E",
                    "value":    "33944",
                    "value2":   "170"

                 },
                 {
                    "name": "Segment F",
                    "value":    "6498",
                    "value2":   "16"
                 }
            ]
        },
        {
            "quarter":  "Q4 2013",
            "values":   [
                {   "name":     "Segment A",
                    "value":    "11228",
                    "value2":   "23"    
                 },
                 {
                    "name": "Segment B",
                    "value":    "31324",
                    "value2":   "83"
                 },
                 {
                    "name": "Segment C",
                    "value":    "1291",
                    "value2":   "17"
                 },
                 {
                    "name": "Segment D",
                    "value":    "4350",
                    "value2":   "17"
                 },
                 {
                    "name": "Segment E",
                    "value":    "52265",
                    "value2":   "155"
                 },
                 {
                    "name": "Segment F",
                    "value":    "23785",
                    "value2":   "66"
                 }
            ]
        },
        {
            "quarter":  "Q1 2014",
            "values":   [
                {   "name":     "Segment A",
                    "value":    "3708",
                    "value2":   "18"
                 },
                 {
                    "name": "Segment B",
                    "value":    "20176",
                    "value2":   "74"
                 },
                 {
                    "name": "Segment C",
                    "value":    "5169",
                    "value2":   "61"
                 },
                 {
                    "name": "Segment D",
                    "value":    "31322",
                    "value2":   "76"
                 },
                 {
                    "name": "Segment E",
                    "value":    "49069",
                    "value2":   "191"
                 },
                 {
                    "name": "Segment F",
                    "value":    "8928",
                    "value2":   "19"
                 }
            ]
        },
        {
            "quarter":  "Q2 2014",
            "values":   [
                {   "name":     "Segment A",
                    "value":    "2950",
                    "value2":   "26"    
                 },
                 {
                    "name": "Segment B",
                    "value":    "6807",
                    "value2":   "54"
                 },
                 {
                    "name": "Segment C",
                    "value":    "3789",
                    "value2":   "110"
                 },
                 {
                    "name": "Segment D",
                    "value":    "12867",
                    "value2":   "91"
                 },
                 {
                    "name": "Segment E",
                    "value":    "21411",
                    "value2":   "128"
                 },
                 {
                    "name": "Segment F",
                    "value":    "18478",
                    "value2":   "21"
                 }
            ]
        }

    ]
            });

            var oScatterPlotHolder = this.byId("RegionScatterPlotHolder");
            var oScatterPlotItem = new vizConcept.ScatterPlotItem({quarter:"{quarter}", values:"{values}"});
            /* new  chart */
            var oScatterPlot = new vizConcept.ScatterPlot({
                items: {path : "/buckets", template : oScatterPlotItem}
            });

            //var oModel = sap.ui.getCore().getModel("growth-regions-scatter");

            oScatterPlot.setModel(oModel);
            oScatterPlotHolder.addItem(oScatterPlot);

            $(function() {
              var dlg = new sap.m.Dialog({
                id: 'vizModal',    
                title: 'Scatter Plot Example Viz',
                width : "1800px",  
                height : "600px",  
                content : [oScatterPlotHolder],
                beginButton: new Button({
                                    text: 'Close',
                                    press: function () {
                                        dlg.close();
                                    }
                                })  
              });

              (new sap.m.Button({
                    text: 'open',
                    type: 'Accept',
                    press: function() {
                      dlg.open();
                      oScatterPlotHolder.invalidate();
                    }
                  })).placeAt('content');
                });

        },    

        onToPage2 : function () {
            this.getOwnerComponent().getRouter().navTo("page2");
        },


        });

        return mainController;
    });

ScatterPlot.js(自定义控件)

jQuery.sap.require("sap/ui/thirdparty/d3");
jQuery.sap.declare("vizConcept.ScatterPlot");

sap.ui.core.Element.extend("vizConcept.ScatterPlotItem", { metadata : {
    properties : {
        "quarter" : {type : "string", group : "Misc", defaultValue : null},
        "values" : {type : "object", group : "Misc", defaultValue : null}   
    }
}});    
sap.ui.core.Control.extend("vizConcept.ScatterPlot", {
    metadata : {
        properties: {
            "title": {type : "string", group : "Misc", defaultValue : "ScatterPlot Title"}
        },
        aggregations : {
            "items" : { type: "vizConcept.ScatterPlotItem", multiple : true, singularName : "item"}
        },
        defaultAggregation : "items",
        events: {
            "onPress" : {},
            "onChange":{}       
        }           
    },


    init : function() {
        console.log("vizConcept.ScatterPlot.init()");
        this.sParentId = "";
    },


    createScatterPlot : function() {
        /*
         * Called from renderer
         */
        console.log("vizConcept.ScatterPlot.createScatterPlot()");
        var oScatterPlotLayout = new sap.m.VBox({alignItems:sap.m.FlexAlignItems.Center,justifyContent:sap.m.FlexJustifyContent.Center});
        var oScatterPlotFlexBox = new sap.m.FlexBox({height:"auto",alignItems:sap.m.FlexAlignItems.Center});
        /* ATTENTION: Important
         * This is where the magic happens: we need a handle for our SVG to attach to. We can get this using .getIdForLabel()
         * Check this in the 'Elements' section of the Chrome Devtools: 
         * By creating the layout and the Flexbox, we create elements specific for this control, and SAPUI5 takes care of 
         * ID naming. With this ID, we can append an SVG tag inside the FlexBox
         */
        this.sParentId=oScatterPlotFlexBox.getIdForLabel();
        oScatterPlotLayout.addItem(oScatterPlotFlexBox);

        return oScatterPlotLayout;

    },


    /**
     * The renderer render calls all the functions which are necessary to create the control,
     * then it call the renderer of the vertical layout 
     * @param oRm {RenderManager}
     * @param oControl {Control}
     */
    renderer : function(oRm, oControl) {
        var layout = oControl.createScatterPlot();

        oRm.write("<div");
        oRm.writeControlData(layout); // writes the Control ID and enables event handling - important!
        oRm.writeClasses(); // there is no class to write, but this enables 
        // support for ColorBoxContainer.addStyleClass(...)

        oRm.write(">");
        oRm.renderControl(layout);
        oRm.addClass('verticalAlignment');

        oRm.write("</div>");

    },

    onAfterRendering: function(){
        console.log("vizConcept.ScatterPlot.onAfterRendering()");
        //console.log(this.sParentId);
        var cItems = this.getItems();
        var data = [];
        for (var i=0;i<cItems.length;i++){
            var oEntry = {};
            for (var j in cItems[i].mProperties) {
                oEntry[j]=cItems[i].mProperties[j];
            }   
            data.push(oEntry);
        }
        //console.log("Data:");
        //console.log(data);

        /*
         * ATTENTION: See .createScatterPlot()
         * Here we're picking up a handle to the "parent" FlexBox with the ID we got in .createScatterPlot()
         * Now simply .append SVG elements as desired
         * EVERYTHING BELOW THIS IS PURE D3.js
         */

        var margin = {
                top: 15,
                right: 15,
                bottom: 30,
                left: 40
            },
            width = 600 - margin.left - margin.right,
                height = 300 - margin.top - margin.bottom;

            // Our X scale
            var x = d3.scale.linear()
                .range([0, width-80]);

            // Our Y scale
            var y = d3.scale.linear()
                .range([height, 0]);

            // Our color bands
            var color = d3.scale.ordinal()
                .range(["#004460", "#0070A0", "#008BC6", "#009DE0", "#45B5E5", "8CCDE9", "#DAEBF2"]);    //"#00A6ED",   

            // Use our X scale to set a bottom axis
            var xAxis = d3.svg.axis()
                .scale(x)
                .orient("bottom");

            // Smae for our left axis
            var yAxis = d3.svg.axis()
                .scale(y)
                .orient("left")
                .tickFormat(d3.format(".2s"));

            var tip = d3.select("body").append("div")
                .attr("class", "sctooltip")
                .style("position", "absolute")
                .style("text-align", "center")
                .style("width", "80px")
                .style("height", "42px")
                .style("padding", "2px")
                .style("font", "11px sans-serif")
                .style("background", "#F0F0FF")
                .style("border", "0px")
                .style("border-radius", "8px")
                .style("pointer-events", "none")
                .style("opacity", 0);

        var vis = d3.select("#" + this.sParentId);
        var svg = vis.append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .style("background-color","white")
        .style("font", "12px sans-serif")
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

        x.domain([0, d3.max(data, function (d) {

            var max = d3.max(d.values, function (dd){
                return(+dd.value);
            })
             return max;
        })]);

        // Our Y domain is from zero to our highest total
        y.domain([0, d3.max(data, function (d) {

            var max = d3.max(d.values, function (dd){
                return(+dd.value2);
            })
            return max;
        })]);

        var totalval = 0;
        var totalval2 = 0;
        data.forEach(function (d) {
            var quarter = d.quarter;
            d.values.forEach(function (dd){
                dd.quarter = quarter;
                totalval += +dd.value;
                totalval2 += +dd.value2;
            });

        });

        var average = totalval/totalval2;
        var line_data = [{"x": 0, "y": 0},{"x": (y.domain()[1]*average), "y": y.domain()[1]}];

        var avgline = d3.svg.line()
            .x(function(d){ return x(d.x); })
            .y(function(d){ return y(d.y); })
            .interpolate("linear");


        svg.append("g")
            .attr("class", "x axis")
            .style("fill", "none")
            .style("stroke", "grey")
            .style("shape-rendering", "crispEdges")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

        svg.append("g")
            .attr("class", "y-axis")
            .style("fill", "none")
            .style("stroke", "grey")
            .style("shape-rendering", "crispEdges")
            .call(yAxis);

        //average line
        svg.append("path")
            .attr("class", "avgline")
            .style("stroke", "#000")
            .style("stroke-width", "1px")
            .style("stroke-dasharray", ("4, 4"))
            .attr("d", avgline(line_data));

        /*
            .append("text")
            .attr("transform", "rotate(-90)")
            .attr("y", 6)
            .attr("dy", ".71em")
            .style("text-anchor", "end")
            .text("XXXXX");
        */
        var plot = svg.selectAll(".quarter")
            .data(data)
            .enter().append("g");

        plot.selectAll("dot")
            .data(function (d) {
            return d.values;
        })
            .enter().append("circle")
            .attr("class", "dot")
            .attr("r", 5)
            .attr("cx", function (d){
                return x(d.value);
            })
            .attr("cy", function (d) {
            return y(d.value2);
        })
            .style("stroke", "#004460")
            .style("fill", function (d) {
            return color(d.name);
        })
            .style("opacity", .9)
            .style("visibility", function(d){
                if(+d.value != 0){
                    return "visible";
                }else{
                    return "hidden";
                }
            })
            .style("pointer-events", "visible")
            .on("mouseover", function(d){
                    tip.transition()
                        .duration(200)
                        .style("opacity", .8);
                    tip.html(d.name + "<br/>" + d.quarter + "<br />" + "Avg. " +(+d.value/+d.value2).toFixed(2))
                        .style("left", (d3.event.pageX-40) + "px")
                        .style("top", (d3.event.pageY-50) + "px");

                })
                .on("mouseout", function(d){
                    tip.transition()
                        .duration(500)
                        .style("opacity", 0);
                });;

        var legend = svg.selectAll(".legend")
        .data(color.domain())
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function (d, i) {
        return "translate(0," + i * 16 + ")";
        });

        legend.append("rect")
        .attr("x", width - 12)
        .attr("width", 12)
        .attr("height", 12)
        .style("fill", color);

        legend.append("text")
        .attr("x", width - 24)
        .attr("y", 6)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .style("font", "11px sans-serif")
        .text(function (d) {
        return d;
        }); 

        var avglabel = svg.append("g")
            .attr("transform", "translate(" + (width-40) + ",140)");
        avglabel.append("text")
            .style("text-anchor", "middle")
            .text("Average: " + average.toFixed(2));

    }
});

以下是双重渲染结果的示例

编辑1(这是我的元素dom树) enter image description here

1 个答案:

答案 0 :(得分:0)

我注意到,根据渲染周期中的生命周期事件可能会很棘手,我认为可以通过UI5来确定何时运行。如果您只想运行一次,那么您可以使用python -m pip install package python3 -m pip install package onRoutePatternMatched(),这些对我来说更加一致。

如果您不想这样做,可以使用全局布尔值并将其设置为onBeforeShow(),这样下次运行时就不会通过测试。像这样:

onAfterRendering()