简体   繁体   English

Javascript变量范围问题-错误:TypeError:this.graphics未定义

[英]Javascript Variable Scope Issue - Error: TypeError: this.graphics is undefined

I know this issue has been done to death, but I still don't understand it. 我知道这个问题已经死了,但是我还是不明白。 I've read StackOverFlow's very own "this" keyword explanation (along with the Mike West article within it) as well as other scope related questions. 我已经阅读了StackOverFlow自己的“ this”关键字说明(以及其中的Mike West文章)以及其他与范围相关的问题。 I don't know why I don't get it, so I look to the more savvy JavaScript developer for help. 我不知道为什么我不明白,所以我向更精明的JavaScript开发人员寻求帮助。

From the code and comments it should be fairly self explanatory. 从代码和注释中,它应该是相当自我解释的。 But it is querying an ESRI map service, returning graphics and placing these on the map. 但是它正在查询ESRI地图服务,返回图形并将其放置在地图上。

But the issue is in the showResults function where I call this.graphics , which is the map's graphics property (a graphics layer). 但是问题出在showResults函数中,我将其称为this.graphics ,这是地图的graphics属性(图形层)。 I'm aware it's now out of scope (which took more time to figure out than I'd like to admit), but how can I put it back in scope so I can use it? 我知道它现在不在范围内(花了更多时间弄清楚我想承认的时间),但是如何才能将其放回范围内以便使用呢? Even if I have alter the code substantially... 即使我已经对代码进行了实质性的更改...

define([
"dojo/_base/declare",
"dojo/on",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dijit/form/Button",
"dijit/form/Form",
"dijit/form/FilteringSelect",
"dijit/form/ValidationTextBox",
"dojo/_base/array",
"dojo/_base/Color",
"dojo/_base/lang",
"esri/tasks/find",
"dojo/text!./Find/templates/Find.html"
], function(declare, on, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Button, Form, FilteringSelect, ValidationTextBox, array, Color, lang, find, FindTemplate) {

//anonymous function to load CSS files required for this module
(function() {
    var css = [require.toUrl("gis/dijit/Find/css/Find.css")];
    var head = document.getElementsByTagName("head").item(0),
        link;
    for(var i = 0, il = css.length; i < il; i++) {
        link = document.createElement("link");
        link.type = "text/css";
        link.rel = "stylesheet";
        link.href = css[i].toString();
        head.appendChild(link);
    }
}());

// Query Dijit
return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
    widgetsInTemplate: true,
    templateString: FindTemplate,
    graphics: null,
    findTask: null,
    findParams: null,
    results: [],
    serverError: null,
    queryLayer: null,
    searchText: null,
    postCreate: function() {
        // Method is used to call a superclass method. It's good practice to assume that you are overriding a method that may 
        // do something important in a class up the inheritance chain
        this.inherited(arguments);

        // Create graphics layer and add it to the map
        this.graphics = new esri.layers.GraphicsLayer({id:"queryGraphics"});
        this.map.addLayer(this.graphics);

        // Create find task with url to map service
        this.findTask = new esri.tasks.FindTask("arcgis/rest/services/MapServer");

        // Create find parameters and define known values
        this.findParams = new esri.tasks.FindParameters();     
        this.findParams.outSpatialReference = this.map.spatialReference;
        this.findParams.returnGeometry = true;
        this.findParams.layerIds = [1];
        this.findParams.searchFields = ["OBJECTID", "Gauge ID", "FV_ID", "FDC_ID", "Flood_Stage", "Flood_Line", "Municipality", "WATERSHED"]; 

        // Listen for Submit button click
        on(this.submitButton, 'click', lang.hitch(this, 'execute'));
    },
    // Submit button click event
    execute: function execute() {   
        // Set the WHERE search text
        this.findParams.searchText = dojo.byId("searchText").value;
        // Sends a request to the ArcGIS REST map service resource to perform a search based 
        // on the FindParameters specified in the findParameters argument. On completion, the 
        // onComplete event is fired and the optional callback function is invoked.
        this.findTask.execute(this.findParams, this.showResults, this.showError); 
    },
    // Fires when the find operation is complete and returns an array of FindResult
    showResults: function showResults(results) {
        this.graphics.clear();
        // Build an array of attribute information and add each found graphic to the map
        dojo.forEach(results, function(result) {
            var symbol;
            switch(result.feature.geometry.type) {
                case "point":
                    symbol = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_CIRCLE, 10, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0]), 1), new Color([255, 0, 0, 1.0]));
                    break;
                case "polyline":
                    symbol = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASH, new Color([255, 0, 0]), 1);
                    break;
                case "polygon":
                    symbol = new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DASHDOT, new Color([255, 0, 0]), 2), new Color([255, 255, 0, 0.0]));
                    break;
                default:
                    symbol = new esri.symbol.SimpleMarkerSymbol(esri.symbol.SimpleMarkerSymbol.STYLE_CIRCLE, 10, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0]), 1), new Color([255, 0, 0, 1.0]));
            }
            var graphic = new esri.Graphic(result.feature.geometry, symbol);
            this.graphics.add(graphic);
        });
    },
    // Fires if the find execution fails to complete
    showError: function showError(serverError) {
        alert("The server encountered an error. Error: " + serverError);
    }
});
});

UPDATE AFTER ANSWERS: 回答后更新:

So, it wasn't one answer that solved this but a combination of two. 因此,解决这个问题的不是一个答案,而是两个答案的结合。 I incorporated Buffalo's answer of 我结合了布法罗的答案

this.findTask.execute(this.findParams, lang.hitch(this, this.showResults), this.showError);

and Buffalo's comment to Craig's answer of 布法罗评论克雷格的回答

dojo.forEach(results, function(result) {  
...
}, this);

but Craig's would have worked here as well. 但克雷格(Craig's)也会在这里工作。 This combined with Tamil's answer I'm most certain would have worked too. 我敢肯定,这与泰米尔人的回答相结合也是可以的。

So I'll mark Buffalo's as the answer, but all three are worth looking at for any further readers. 因此,我将Buffalo标记为答案,但所有这三者对于任何进一步的读者都是值得关注的。

You could use Function.bind (Beware! its not supported in all the browsers). 您可以使用Function.bind (请注意,并非所有浏览器都支持它)。

Change: 更改:

this.findTask.execute(this.findParams, this.showResults, this.showError); 

To: 至:

this.findTask.execute(this.findParams, this.showResults.bind(this), this.showError); 

Or(If you are concerned about Function.bind browser support): 或(如果您担心Function.bind浏览器支持):

Use closure & Function.apply 使用closureFunction.apply

execute: function execute() {  
...
...
  var self = this;
  this.findTask.execute(this.findParams, function() {
    self.showResults.apply(self, arguments);
  }, this.showError); 
}

The hitch method in dojo/_base/lang is going to be your best friend here. dojo/_base/langhitch方法将是您最好的朋友。 What I assume the findTask function does is exceucte some asynchronous request and then invokes the 2nd param with the results. 我假设findTask函数所做的是执行一些异步请求,然后使用结果调用第二个参数。

First, add dojo/_base/lang to your Dependency list. 首先,将dojo/_base/lang添加到您的“依赖关系”列表中。

Then, change the line 然后,换行

this.findTask.execute(this.findParams, this.showResults, this.showError); 

to

this.findTask.execute(this.findParams, lang.hitch(this,this.showResults), this.showError); 

What lang#hitch does is take the first parameter (in this case the instance of your widget), and make it be the scope when the second parameter executes. lang#hitch所做的是获取第一个参数(在本例中为小部件的实例),并使其成为执行第二个参数时的作用域。 In this case we want showResults to execute in the current scope. 在这种情况下,我们希望showResults在当前范围内执行。

Your problem is with the following code 您的问题是以下代码

    dojo.forEach(results, function(result) {

        ...

        this.graphics.add(graphic);
    });

the function being executed does not have the scope of the widget. 执行的函数没有小部件的范围。 Make it: 做了:

    dojo.forEach(results, lang.hitch(this, function(result) {

    }));

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

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