Howdy all,
An easy question for the pros:
In the "LayerList widget with actions" sample code (https://developers.arcgis.com/javascript/latest/sample-code/widgets-layerlist-actions/index.html) the code gives some actions to a layer. I've modified that example to add a "save" button that writes a cookie with the currently visible layers, so I can reload the page and have my new default layers be visible. However, when I add more layers, the save button shows up on each layer and each sublayer. I was looking for a way to have the save button appear once, but I don't really want it as part of any specific layer. Is there a way to do this?
This is what I have so far:
//LayerListWidget initialization
var layerList = new LayerList({
view: view,
listItemCreatedFunction: onLayerWidgetStartup
});
function onLayerWidgetStartup(event) {
var item = event.item;
item.actionsSections = [[{
title: "Save Layer visibility",
className: "esri-icon-save"
}]];
//rest of stuff to write cookies
Since I'm calling onLayerWidgetStartup for each listItem, I get a Save Layer button on each.
Solved! Go to Solution.
Greg,
As you probably know there is no overall menu for the LayerList widget so you would have to manually create something and add it to the widgets domNode. So it would take something like this:
var layerList = new LayerList({
view: view,
// executes for each ListItem in the LayerList
listItemCreatedFunction: defineActions
});
watchUtils.whenDefinedOnce(layerList, "viewModel", function(evt){
var mydom = domConstruct.toDom("<a class='saveLink' href='#'>Save</a>");
setTimeout(function(){
domConstruct.place(mydom, query('.esri-layer-list')[0], "first");
on(query('.saveLink')[0],'click', function(){
console.info("save button clicked");
});
}, 200);
});
Greg,
Are you saying that you do not want the children of the layer to get the action? If so then just check if the item.children property. If it is a collection then you are dealing with a parent element if it does not then you should not add the action.
I don't want each Parent layer (or their children) to get the action. Instead, I would like for the whole LayerlistWidget to get the action.
The "save" action loops through each layer (and sublayer) and checks if the property visible=true. When it finds one that is on, it saves that layer.title into an array. The cookie is generated from the array.
edit: I don't need each layer to have a button that loops through the whole array, only one button for the whole widget
Greg,
As you probably know there is no overall menu for the LayerList widget so you would have to manually create something and add it to the widgets domNode. So it would take something like this:
var layerList = new LayerList({
view: view,
// executes for each ListItem in the LayerList
listItemCreatedFunction: defineActions
});
watchUtils.whenDefinedOnce(layerList, "viewModel", function(evt){
var mydom = domConstruct.toDom("<a class='saveLink' href='#'>Save</a>");
setTimeout(function(){
domConstruct.place(mydom, query('.esri-layer-list')[0], "first");
on(query('.saveLink')[0],'click', function(){
console.info("save button clicked");
});
}, 200);
});
Thank you very much Robert, this is exactly the kind of thing I was looking for. I didn't realize LayerList didn't have an overall menu. However, I'm having trouble making the code work. By adding a bunch of console.log("") lines, I've figured out that the watchUtils.whenDefinedOnce() function is not firing. Where in my code should this snippit go? I've placed it after
view.then(function () {
var layerList = new LayerList({
view: view,
listItemCreatedFunction: onLayerWidgetStartup //this is my defineActions function
});
view.ui.add(layerList, "top-left");
//Your snippit
with view being a mapView object. Thanks in advance for taking a look at this
Greg,
You should notice in my snippet I am not using listItemCreatedFunction as there is no need since you are not wanting to add an action to a individual layer. Just do as I did in my snippet.
I added your snippit inside of the view.then() function, not into the listItemCreatedFunction. The reason I did is because the ARCGIS example for the LayerList widget (https://developers.arcgis.com/javascript/latest/sample-code/widgets-layerlist/index.html) initializes the widget inside that function. I simply added your snippit below that. When I tried to take the layerList initialization and your snippit outside of view.then() function, I got an error saying "object does not support method whenDefinedOnce". Very strange, since I know .whenDefinedOnce() is is part of watchUtils.
Note: I also included "esri/core/watchUtils" in the require bracket
Again, thank you for taking a look at this.
Greg,
You must have something off in your code then. Can you post what you have for review?
Sure, here it is. I don't know how to put it in the fancy box with numbered lines like your replies.
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/TileLayer",
"esri/widgets/LayerList",
"esri/core/watchUtils",
"dojo/dom",
"dojo/on",
"dojo/domReady!"
], function (
Map, MapView, FeatureLayer, TileLayer, LayerList, dom, on, watchUtils
) {
var featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0"
});
var transportationLyr = new TileLayer({
url: "https://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Transportation/MapServer",
// This property can be used to uniquely identify the layer
id: "streets",
});
//initialize the map object
var map = new Map({
basemap: "hybrid"
});
map.add(featureLayer);
map.add(transportationLyr);
//set up the viewing object and inital viewport
var view = new MapView({
container: "viewDiv", // Reference to the DOM node that will contain the view
map: map, // References the map object
extent: { // autocasts as new Extent()
xmin: -9177811,
ymin: 4247000,
xmax: -9176791,
ymax: 4247784,
spatialReference: 102100
}
});
//LayerListWidget initialization
var layerList = new LayerList({
view: view,
listItemCreatedFunction: onLayerWidgetStartup
});
view.ui.add(layerList, "top-left");
watchUtils.whenDefinedOnce(layerList, "viewModel", function (evt) {
var mydom = domConstruct.toDom("<a class='saveLink' href='#'>Save</a>");
setTimeout(function () {
domConstruct.place(mydom, query('.esri-layer-list')[0], "first");
on(query('.saveLink')[0], 'click', function () {
console.info("save button clicked");
});
}, 200);
});
view.then(function () {
layerList.on("trigger-action", function (event) {
var id = event.action.title;
//this is what is called when the save button is hit.
//If I undersand your snippit, I would paste over the
//the console.info("save button clicked"); command.
if (id === "Save Layer visibility") {
var item = event.item;
var operationalItemCollection = layerList.operationalItems;
var visibleLayersArray = CheckVisibleProperty(operationalItemCollection);
document.cookie = setCookie("CustomDefaultLayers", visibleLayersArray.join("|"));
}
});
});
//helper function to create visibleLayersArray
function CheckVisibleProperty(passedCollection) {
var passedArray = passedCollection.toArray();
var resultArray = new Array();
for (var i = 0; i < passedArray.length; i++) {
if (passedArray.visible === true) {
if (passedArray.children.length != 0) {
var tempArray = CheckVisibleProperty(passedArray.children);
resultArray = resultArray.concat(tempArray);
}
resultArray.push(passedArray.title);
}
}
return resultArray;
}
//I belive the onLayerWidgetStartup() can be commented out since the
//function only lets me read the cookies made and I know
//this part works
//helper function to initialize the layerList widget
function onLayerWidgetStartup(event) {
var item = event.item;
//initializeing the visibility of the layers on startup
item.visible = false;
if (checkCookie()) //check cookie is defined in the cookieMonster
{
var resultString = getCookie("CustomDefaultLayers");
if (resultString.indexOf(item.title) != -1) {
item.visible = true;
}
//defaultVisibleLayers is defined as a JSON object in another .js file
} else {
if (defaultVisibleLayers.indexOf(item.title) != -1) { //string.indexOf() reference https://www.w3schools.com/jsref/jsref_indexof.asp
item.visible = true;
}
}
}
});
Greg,
So what you will have to learn about JS coding (AMD style) is that your require array list needs to align with your variable list.
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/layers/TileLayer",
"esri/widgets/LayerList",
"esri/core/watchUtils",
"dojo/dom",
"dojo/on",
"dojo/domReady!"
], function (
Map, MapView, FeatureLayer, TileLayer, LayerList, watchUtils, dom, on
) {