Technically, no, you need to have a tiled or dynamic layer in your map first. We're looking at changing this in a future release so that you can use a feature layer (or graphics layer) as the only layer in the map. Until then, you can extend dynamic map service layer to create a custom layer that doesn't do anything. Basically, you override getImageUrl to do nothing like this: getImageUrl: function(extent, width, height, callback) { // do nothing...we want an empty layer }
Here's simple example of a map with a custom dynamic layer that doesn't do anything and a feature layer: http://jsfiddle.net/n7r4D/Full code sample: <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/> <title></title> <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/dojo/dijit/themes/tundra/tundra.css"> <link rel="stylesheet" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.7/js/esri/dijit/css/Popup.css"> <style> html, body { height: 100%; width: 100%; margin: 0; padding: 0; } #map{ margin: 0; padding: 0; } </style> <script>var dojoConfig = { parseOnLoad: true };</script> <script src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.7"></script> <script> dojo.require("dijit.layout.BorderContainer"); dojo.require("dijit.layout.ContentPane"); dojo.require("esri.map"); dojo.require("esri.layers.FeatureLayer"); var map; function init() { map = new esri.Map("map",{ "slider": false }); dojo.connect(map, "onLoad", function() { dojo.connect(dijit.byId("map"), "resize", map, map.resize); }); // add an empty layer var el = new easy.EmptyLayer({ wkid: 102003 }); map.addLayer(el); dojo.connect(el, "onLoad", function() { // add a feature layer addStatesFeatureLayer(); }); } function addStatesFeatureLayer() { // sym and renderer var outline = new esri.symbol.SimpleLineSymbol() .setColor(dojo.colorFromHex("#fff")); var sym = new esri.symbol.SimpleFillSymbol() .setColor(new dojo.Color([52, 67, 83, 0.4])) .setOutline(outline); var renderer = new esri.renderer.SimpleRenderer(sym); // create and add the actual FL fl = new esri.layers.FeatureLayer("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5", { mode: esri.layers.FeatureLayer.MODE_ONDEMAND, outFields: ["STATE_NAME", "POP2000", "POP2007"], maxAllowableOffset: (map.extent.getWidth() / map.width) }); fl.setRenderer(renderer); map.addLayer(fl); } // extend dynamic map service layer to create an empty layer dojo.declare("easy.EmptyLayer", esri.layers.DynamicMapServiceLayer, { constructor: function(params) { this.params = params || {}; this.wkid = this.params.wkid || 102100; this.spatialReference = new esri.SpatialReference({ wkid: this.wkid }); // extent for contiguous US var ext = new esri.geometry.Extent({ "xmin":-14325844, "ymin":2207331, "xmax":-7121642, "ymax":6867214, "spatialReference":{ "wkid": 102100 } }); if ( this.wkid != ext.spatialReference.wkid ) { // project extent for contiguous US to the supplied wkid var gs = new esri.tasks.GeometryService('http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/Geometry/GeometryServer'), that = this; gs.project([ext], this.spatialReference, function(result) { // console.log('projected extent: ', result, that); that.initialExtent = that.fullExtent = result[0]; that.loaded = true; that.onLoad(that); }); } else { // console.log('no need to project'); this.initialExtent = this.fullExtent = ext; this.loaded = true; this.onLoad(this); } }, getImageUrl: function(extent, width, height, callback) { // do nothing...we want an empty layer } }); dojo.ready(init); </script> </head> <body class="tundra"> <div data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design:'headline',gutters:false" style="width: 100%; height: 100%; margin: 0;"> <div id="map" data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'center'"> </div> </div> </body> </html>