简体   繁体   English

ASP.NET渲染控件-> JavaScript错误

[英]Asp.net render control -> javascript error

I have a usercontrol with some charts from Google chart api. 我有一个来自Google Chart API的图表用户控件。

When the usercontrol is getting loaded and rendered by the server the usual way everything works as expected. 当用户控件由服务器加载和呈现时,一切正常,一切正常。 But when I use a ajax webservice the render the control async and return the html with ajax and add it to the page, I get some script error in firebug(chrome calls it a ReferenceError): 但是当我使用ajax Web服务渲染控件异步并返回带有ajax的html并将其添加到页面时,我在firebug中遇到了一些脚本错误(chrome将其称为ReferenceError):

"google is not defined" “未定义Google”

图片

My project is ASP.Net MVP Webforms with some javascript. 我的项目是带有一些javascript的ASP.Net MVP Webforms。
I have made a sample project where I have recreated the issue. 我做了一个示例项目,在其中重新创建了问题。 Download it here . 在这里下载

Control renderer code: 控制渲染器代码:

public virtual string RenderControlToString(string path, bool htmlEncode)
{
    StringWriter stringWriter = new StringWriter();
    this.RenderControl(path, (TextWriter)stringWriter);
    string s = stringWriter.ToString();
    if (!htmlEncode)
        return s;
    else
        return HttpContext.Current.Server.HtmlEncode(s);
}

public virtual void RenderControl(string path, TextWriter writer)
{
    var page = new PageForRendering();
    page.Controls.Add(page.LoadControl(path));
    HttpContext.Current.Server.Execute((IHttpHandler)page, writer, true);
}

(To omit the "need to be in form" error - there is a form on the page the control is added to) (要忽略“表单需要”错误-控件添加到的页面上有一个表单)

public class PageForRendering : Page
{
    public override void VerifyRenderingInServerForm(Control control)
    {}
}

Script on the usercontrol: 用户控件上的脚本:

<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    console.log("Loading Google Charts...");
    google.load('visualization', '1.0', { 'packages': ['corechart'] });
    console.log("Google Charts loaded!");

    google.setOnLoadCallback(function () {
        ...some code...
    });
</script>

With firebug I found out that https://www.google.com/jsapi is loaded fine but only the first one of my console logs is printed. 使用firebug时,我发现https://www.google.com/jsapi加载正常,但是仅打印了我的第一个控制台日志。

I think it might be some kind of scope issue... The google variable will be defined in this script: 我认为这可能是某种范围问题... google变量将在此脚本中定义:

<script type="text/javascript" src="https://www.google.com/jsapi"></script>

But in this case it is inaccessible in the next script block. 但是在这种情况下,下一个脚本块将无法访问它。 With normal rendering it works normally. 使用普通渲染,它可以正常工作。 Either the script isn't done loading before the google.load call or the google variable is now somehow defined in another scope because of the different rendering method. 由于呈现方法不同,因此在google.load调用之前脚本未完成加载,或者google变量现在已以其他方式定义在另一个作用域中。

If I look in firebug DOM the google variable is defined like here . 如果我看的萤火DOM谷歌的变量定义喜欢这里 But I found out that if I place a break point a the line: google.load('visualization', '1.0', { 'packages': ['corechart'] }); 但是我发现,如果我在断点处放置一条线: google.load('visualization', '1.0', { 'packages': ['corechart'] }); , I find that at this moment the google variable is not defined in the DOM. ,我发现目前google变量未在DOM中定义。 So it might also be somethink about loading the script. 因此,可能还需要考虑加载脚本。 But the line <script type="text/javascript" src="https://www.google.com/jsapi"></script> is before it and it should be executed synchronzly right? 但是行<script type="text/javascript" src="https://www.google.com/jsapi"></script>在它之前,应该同步执行吗? When I check the Net in firebug I also find that the file is downloaded correctly. 当我在Firebug中检查网络时,我还发现该文件已正确下载。

I might also need to mention that the usercontrol loading ajax code looks like this: 我可能还需要提及的是,加载ajax代码的usercontrol如下所示:

<div id="statisticsContent">&nbsp;</div>

<script type="text/javascript">
    $(document).ready(function () {
        function getStatisticsView() {
            var id = $(".chooseStatisticsToShow input:radio:checked").val();
            var statisticsType = (id == $(".choosePlayingGroupDropDownList option:selected").val() ? 1 : 0);

            $.ajax({
                cache: false,
                global: false,
                type: "POST",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                url: '/Services/StatisticsService.svc/GetStatisticsView',
                data: JSON.stringify({
                    statisticsType: statisticsType,
                    id: id
                }),
                success: function (data) {
                        $("#statisticsContent").html(data.d.ViewHtml);
                }
            });
        }
        getStatisticsView();

        $(".chooseStatisticsToShow").change(function () {
            getStatisticsView();
        });
    });
</script>



I have made a sample project where I have recreated the issue. 我做了一个示例项目,在其中重新创建了问题。 Download it here . 在这里下载

After your service sent response and you added it using $("#statisticsContent").html(data.d.ViewHtml); 服务发送响应并使用$("#statisticsContent").html(data.d.ViewHtml);添加响应后$("#statisticsContent").html(data.d.ViewHtml); browser interprets html and starts loading and executing scripts in parallel. 浏览器解释html并开始并行加载和执行脚本。 How do I know it? 我怎么知道 Just experience - in my projects every time I was trying to inject <script src='...'> browsers were not waiting for scripts to load and next script tags with custom code were executed immediately. 只是经验-在我的项目中,每次我尝试注入<script src='...'>浏览器都不等待脚本加载,并且立即执行带有自定义代码的下一个script标记。

This is your case and you need to wait for jsapi to load and only then execute code that will load package and perform chart rendering. 这是您的情况,您需要等待jsapi加载,然后才执行将加载包并执行图表渲染的代码。 Here is the code: 这是代码:

<div id="chart_div"></div>

<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    waitForGoogleApiAndLoadPackages();
    function waitForGoogleApiAndLoadPackages() {
        if (typeof (google) === 'undefined')
            setTimeout(waitForGoogleApiAndLoadPackages, 100);
        else {
            google.load('visualization', '1.0', { 'callback': 'renderChart', 'packages': ['corechart'] });
        }
    }

    function renderChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Topping');
        data.addColumn('number', 'Slices');
        data.addRows([['Mushrooms', 3], ['Onions', 1], ['Olives', 1], ['Zucchini', 1], ['Pepperoni', 2]]);

        var options = { 'title': 'How Much Pizza I Ate Last Night', 'width': 400, 'height': 300 };

        var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
        chart.draw(data, options);
    }
</script>

Another interesting part is else block in waitForGoogleApiAndLoadPackages function. 另一个有趣的部分是waitForGoogleApiAndLoadPackages函数中的else块。 This is a workaround for issue described in Why does google.load cause my page to go blank? 这是解决问题的一种变通方法, 为什么google.load导致我的页面空白? question. 题。


Quote from Why does google.load cause my page to go blank? 引用自为何google.load导致我的页面空白? :

Looks like google.load is adding the script to the page using a document.write(), which if used after the page loads, wipes out the html. 看起来google.load正在使用document.write()将脚本添加到页面,如果在页面加载后使用脚本,则会清除html。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM