Show the attribute inspector without saving a new feature - javascript

The requirement is to add a new feature from template picker but without applying it, can i show the attribute inspector than save the feature.
selectedTemplate = templatePicker.getSelected();
This selectedTemplate is then selected to put the points on the map than opens the attribute inspector by selecting it.
selectedTemplate.featureLayer.applyEdits([newGraphic], null, null);
Sample Code Block :
dojo.connect(drawToolbar, "onDrawEnd", function(geometry) {
//display the editable info window for newly created features
if (map.infoWindow.isShowing) {
map.infoWindow.hide();
}
drawToolbar.deactivate();
var fieldAttributes = layerFieldToAttributes(selectedTemplate.featureLayer.fields);
var newAttributes = dojo.mixin(fieldAttributes, selectedTemplate.template.prototype.attributes);
var newGraphic = new esri.Graphic(geometry, null, newAttributes);
var layerInfos = [{
'featureLayer': selectedTemplate.featureLayer,
'isEditable': true
}];
var attInspector = new esri.dijit.AttributeInspector({
layerInfos: layerInfos
}, dojo.create("div"));
selectedTemplate.featureLayer.applyEdits([newGraphic], null, null, function() {
var screenPoint = map.toScreen(getInfoWindowPositionPoint(newGraphic));
map.infoWindow.setContent(attInspector.domNode);
map.infoWindow.resize(325, 185);
map.infoWindow.show(screenPoint, map.getInfoWindowAnchor(screenPoint));
templatePicker.clearSelection();
});
dojo.connect(attInspector, "onAttributeChange", function(feature, fieldName, newFieldValue) {
feature.attributes[fieldName] = newFieldValue;
feature.getLayer().applyEdits(null, [feature], null);
});
dojo.connect(attInspector, "onDelete", function(feature) {
feature.getLayer().applyEdits(null, null, [feature]);
map.infoWindow.hide();
});
});
}
I would like my client first add the attribute to feature and (save & apply) it.
Any help would be appreciated.
Here is the sample project : https://www.dropbox.com/s/fh71g1k9nsa70nq/index-2.html.zip?dl=0

I dont think you can do that with the AttributeInspector, try creating a custom popup that will have options to save and delete/cancel, when saving fire the applyEdits, when clicking delete, remove, ect.
Content:
var content = "<input id='text1'></input> </br>" +
"<input id='text1'></input> </br>" + "<button id='submit'>Submit</button>" + "<button id='delete'>Delete</button>"
/*
var attInspector = new AttributeInspector({
layerInfos: layerInfos
}, dojo.create("div"));
*/
map.infoWindow.setTitle(selectedTemplate.featureLayer.name);
map.infoWindow.setContent(content);
map.infoWindow.resize(350, 240);
map.infoWindow.show(evt.geometry, map.getInfoWindowAnchor(evt.geometry));
Listener:
on(map.infoWindow, "show", function () {
on(dom.byId("submit"), "click", function () {
alert("I should be saving");
});
on(dom.byId("delete"), "click", function () {
alert("I should be deleting");
});
})
Check out this fiddler: https://jsfiddle.net/kreza/jpLj5y4h/2/

Related

Creating popup window and displaying data

I'm moving from OpenLayers 2 to OpenLayers 6 in my project.
In the OpenLayers 2 project when I click on a feature in a
vector layer I get the description of the feature in a popup window.
Here is the code:
function createVectorLayer(layer) {
var l = new OpenLayers.Layer.Vector(
layer.Title,
{
eventListeners: {
'featureselected': function (evt) {
var f = evt.feature;
var popup = new OpenLayers.Popup.FramedCloud("popup",
//OpenLayers.LonLat.fromString(f.geometry.toShortString()),// Michael commented 25/02/2018
OpenLayers.LonLat.fromString(f.geometry.getCentroid().toShortString()),
null,
"<div style='font-size:.8em'>" + f.attributes.Description + "<br/><a href='#picturedFeatureEditor' class='ui-btn ui-mini' id='featureEditButton'>עדכון</a></div>",
null,
true
);
f.popup = popup;
map.addPopup(popup);
$("#featureEditButton").click(function () {
editableFeature = f.attributes;
editableFeatureObject = f;
initFeatureEditor();
//$.mobile.changePage("#picturedFeatureEditor");
});
},
'featureunselected': function (evt) {
var feature = evt.feature;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
},
}
);
return l;
}
Here is how I create a Vector layer in OpenLayers 6:
function createVectorLayer(layer) {
var source = new ol.source.Vector({
loader: dataServices.getFeatures(layer.Id,
function (response) {
if (!response) return;
var features = [];
$(response).each(function (i, j) {
let shapeObject = getShapeObject(j);
let feature = new ol.Feature({ 'geometry': shapeObject });
features.push(feature);
});
source.addFeatures(features);
},
function (jqXhr, textStatus, errorMessag) {
console.log(errorMessag);
})
});
return new ol.layer.Vector({
source: source,
style: createStyle(source)
});
}
I know that I can create a popup using Overlay and ol.interaction.Select
which is fired when the feature is clicked, but I don't know how to access the feature description when the feature is clicked to display it in the popup.
My question is how I can implement the same behaviour using OpenLayers 6 (i.e. how to implement feature popups in 6)?
You can add properties to the feature in the constructor (assuming the data is available from your dataServices):
let feature = new ol.Feature({
geometry: shapeObject,
description: ....
});
which can then be accessed using feature.get('description') or feature.getProperties().description
If you are using a Select interaction
select.on('select', function(event) {
if (event.selected.length > 0) {
var feature = event.selected[0];
var description = feature.get('description');
}
});
You can look at the ol-ext FeaturePopup.
See example: https://viglino.github.io/ol-ext/examples/popup/map.popup.feature.html
Or https://viglino.github.io/ol-ext/examples/popup/map.popup.html

Error: cannot call methods on tabs prior to initialization; attempted to call method 'destroy'

I'm working on updating an older site to the newer version of jQuery and applying bootstrap.
We are using
backbone.js
jQueryui and
bootstrap.js.
I am getting the following error: Error: cannot call methods on tabs prior to initialization; attempted to call method 'destroy'
The lines of code it is related to is:
Thanks
define([
'jquery',
'jqueryui',
'underscore',
'backbone',
'vm',
'events',
'models/product',
'text!templates/editor/page.html'
], function ($, jui, _, Backbone, Vm, Events, Product, PageTemplate) {
var EditorPage = Backbone.View.extend({
model: Product,
el: '#editor',
_$editorErrorContainer: undefined,
events: {
"click #toolbar": "onToolbarClicked"
},
initialize: function () {
this.bindSaveEvents();
Events.unbind("addText");//HACK: Prevents zombie listeners for this specific situation
Events.bind("addText", this.onAddText, this);
},
onAddText: function (e) {
var layers = this.model.get('layers');
var textCollections = [];
//Search for valid text collections in our layer and push into our array
layers.models.forEach(function (layer) {
var tc = layer.get("textCollection");
if (typeof tc !== "undefined") {
if (layer.get("allowText")) {
var printColor = layer.get("printColor");
var src;
if(printColor) { src = printColor.get("src"); }
var _tc = { 'textCollection': tc, 'src': src, 'name':layer.get('name'), 'cid': layer.cid };
textCollections.push(_tc);
}
}
});
//if there's no choice to make, just add the text element.
if (textCollections.length == 1) {
var textCollection = textCollections[0].textCollection;
AddTextToCollection(textCollection);
return;
}
//Otherwise create dialog for choosing in which text collection to put a new text object
var dialogHTML = "<div> <p>What color would you like this text?</p>";
//Generate selections, use the src attribute of the print color if it uses printcolor
//TODO use other attributes of a textCollection such as rgb color if it uses it etc
textCollections.forEach(function (textCollection, i) {
var imgurl = "";
if(textCollection.src) {
imgurl = "/productEditor/assets/printcolors/icons/" + textCollection.src;
}
//Customers wont like zero indexed option names
var id = i + 1;
dialogHTML += "<p data-id= " + i + " class='selection'> Group " + id + ": " + textCollection.name + "<img src='" + imgurl + "'/> </p>";
});
dialogHTML += "</div>"
$(dialogHTML).dialog({
modal: true,
width: "25%",
height: "auto",
dialogClass: "textAddDialog",
resizable: false,
position: {
my: 'left top',
at: 'left top',
of: $("#editor"),
collision: 'flip'
},
show: 'fade',
create: function() {
var that = this;
//bind dialog events
$(this).children(".selection").click(function(){
$(that).children('.selected').removeClass("selected");
$(this).addClass("selected");
});
},
open: function (event, ui) {
$('.ui-dialog').css('z-index',2003);
$('.ui-widget-overlay').css({
'z-index': 2002,
'opacity': 0.5
});
},
close: function() {
$(this).children(".selection").unbind();
$(this).dialog('destroy').remove();
},
buttons: [{
text: "Accept",
"class": "acceptButton",
click: function() {
var index = $(this).children('.selected').data('id');
if(index >= 0) {
var textCollection = textCollections[index].textCollection;
AddTextToCollection(textCollection);
}
$(this).dialog("close");
}
},
{
text: "Cancel",
click: function() {
$(this).dialog("close");
}
}
]
});
function AddTextToCollection (textCollection) {
//Create text element in chosen group
var entry = textCollection.createEntry();
//Show user that this is a fresh text element that needs changing
entry.set("text", "Edit Me!");
entry.set("freshElement", true);//Fresh element denotes a completely new element, used to delete this element if user adds an element -> cancel button
//Trigger mouseup on element so our text editor dialog will pop for this element
var elem = $('.text_modifier[data-cid="' + entry.cid + '"]');
elem.trigger("click");
}
},
bindSaveEvents: function(){
Events.on('saveError', this.onSaveError.bind(this));
Events.on('saveSuccess', this.onSaveSuccess.bind(this));
},
unbindSaveEvents: function(){
Events.off('saveError', this.onSaveError.bind(this));
Events.off('saveSuccess', this.onSaveSuccess.bind(this));
},
onToolbarClicked: function (e) {
//console.log("toolbar clicked");
//this._productView.clearSelectedChildren();
},
onSaveError: function(errorMessage){
// if(this._$editorErrorContainer === undefined){
// this._$editorErrorContainer = $("<div/>").addClass("error");
// $(this.el).before(this._$editorErrorContainer);
// }
// this._$editorErrorContainer.text(errorMessage).show();
$('#appError').text(errorMessage).show();
},
onSaveSuccess: function(){
// if(this._$editorErrorContainer != null){
// this._$editorErrorContainer.hide();
// }
$('#appError').hide();
},
onRenderComplete: function (e) {
// ADD THE RETURN ELEMENT TO THE LIST OF
this._loadList = _.without(this._loadList, e);
if (this._loadList.length == 0) {
$(this.el).removeClass('loading');
}
},
remove: function(){
this.unbindSaveEvents();
},
renderApp: function () {
var that = this;
// PUT LIST OF ITEMS THAT RENDER INTO ARRAY
// renderComplete WILL REMOVE ITEMS, AND CHANGE STATE TO VISIBLE WHEN ALL ARE LOADED
this._loadList = ['layer', 'product', 'modifiers', 'tabs']
// CREATE PREVIEW MODIFIERS
require(['views/modifiers/product'], function (PreviewModifierView) {
that._modifierView = new PreviewModifierView({ model: that.model });
that._modifierView.on("renderComplete", that.onRenderComplete, that);
that._modifierView.render();
});
// CREATE PREVIEW
require(['views/preview/product'], function (PreviewProductView) {
that._productView = new PreviewProductView({ model: that.model });
that._productView.on("renderComplete", that.onRenderComplete, that);
that._productView.render();
});
// CREATE PRODUCT NAME DISPLAY
require(['views/toolbar/productname'], function (ProductNameView) {
that._productNameView = new ProductNameView({ model: that.model });
that._productNameView.render();
});
// CREATE PRODUCT DESCRIPTION DISPLAY
require(['views/toolbar/productdescription'], function (ProductDescView) {
that._productDescriptionView = new ProductDescView({ model: that.model });
that._productDescriptionView.render();
});
// CREATE TOOLBAR
require(['views/toolbar/layer'], function (ToolbarLayerView) {
that._toolbarView = new ToolbarLayerView({ model: that.model });
that._toolbarView.on("renderComplete", that.onRenderComplete, that);
that._toolbarView.render();
});
// CREATE FINISHED BUTTON
require(['views/toolbar/finished'], function (FinishedView) {
that._finishedView = new FinishedView({ model: that.model });
that._finishedView.render();
});
// CREATE TABS
require(['views/tabs/product'], function (TabsView) {
that._tabsView = new TabsView({ model: that.model });
that._tabsView.on("renderComplete", that.onRenderComplete, that);
that._tabsView.render();
});
},
render: function () {
//console.log("editor render!");
//console.log(this.model);
//$('#productName').html(this.model.get);
var pageTemplate = _.template(PageTemplate, this);
$(this.el).html(pageTemplate);
$('#button-editor-help').show(); // GET'S HIDDEN ON THE APPROVAL PAGE
this.renderApp();
}
});
return EditorPage;
});
In the tabs view, hook up a debugger where you call the destroy and create
Replicate the bug and check if you are calling destroy before initialization
May be you are calling close before the dialog is initialised.

Click function doesn't work after ajax call in dynamic element (Backbone)

I've create dynamic popup in my Backbone.view by clicking button:
var Section = Backbone.View.extend({
className: 'sqs-frontend-overlay-editor-widget-section',
events:{
'click .sqs--section--control__edit': 'Section_control'
},
initialize: function(){
},
render: function(){
this.$el.append(_.template(_section).apply(this.options));
return this.$el;
},
Section_control: function(){
var me = this;
require(['View/Popup/Section_control'], function(_Section_control){
var sec = new _Section_control({popup: popup, sec: me.options.section});
var popup = new Popup({content: sec.render()});
});
}
});
return Section;
in the created dynamic popup i have button with trigger:
events:{
'click .module-invert-mode': 'invert'
},
invert: function(e){
console.log('hello');
if(this.options.sec.hasClass('.module-invert')) {
console.log('yse');
}
this.options.sec.toggleClass('module-invert');
this.options.sec.trigger('invertChange');
},
and button invertChange trigger:
el.on("invertChange", function(e){
var section = el.parents('section');
var index = section.index();
var model = collection.at(index);
model.set(Helper.sectionToObj(section),{doReload: true})
});
take a look at the {doReload: true} function that i call in invertChange:
change: function(model, options){
me = this;
if( model._changing && options.doReload ) {
$.ajax({
url: 'wp-admin/admin-ajax.php',
type: 'post',
data: {
action: 'getShortcode',
shortcode: model.attributes.shortcode
},
success: function (data) {
//var section = $(data);
me.$el.find('section:eq(' + model.collection.indexOf(model) + ')').replaceWith(data);
me.add( model, model.collection );
//me.collection.add({shortcode: model.attributes.shortcode}, {at: section.index()});
}
});
}
},
the problem is when I create dynamic popup and click on the button with invertChange trigger, ajax works only once, when I click on button in popup again, ajax doesn't works ( next ajax request works only if close and create dynamic popup again). How I can call ajax without constantly closing and opening my dynamic popup?
The problem that you have code which overrides child views
me.$el.find('section:eq(' + model.collection.indexOf(model) + ')').replaceWith(data);
And this listener is not able to handle event
el.on("invertChange", function(e){
because your code
this.options.sec.trigger('invertChange');
doesn't trigger event on correct view, it has lost the reference to this view after replaceWith()
As a solution you need parse your data object and apply each changes locally to elements
something like this
$(data).find("* [attr]").each(function(i, el) {
var $el = $(el),
attr = $el.attr("attr"),
$parent = me.$el.find('section:eq(' + model.collection.indexOf(model) + ')');
if ($el.is("div, span")) {
$parent.find('[attr=' + attr + ']').html($el.html());
} else if ($el.is("img")) {
$parent.find('[attr=' + attr + ']').attr("src", $el.attr("src"));
} else if ($el.is("a")) {
$parent.find('[attr=' + attr + ']').attr("href", $el.attr("href"));
} else if (attr == "image_back_one") {
$parent.find('[attr=' + attr + ']').attr("style", $el.attr("style"));
} else {
console.log($el);
}
});

Enabling History API with datatables

I have a dataTable object on a page representing a list of releases I need to keep track of with the url /releases I want to add the following functionality
if /releases?query=<query>, the dataTable will initialized with the provided query
The query parameter is updated if the user changes the search term
The back and forward buttons in the browser go the appropriate query
So far I am able to do the first 2, but when I listen for the popstate event, redrawing the table triggers a pushState which I can't figure out how to prevent. Here's my code so far:
$(document).ready(function(){
var prevSearch;
var table = $('#releases').dataTable({
"bJQueryUI" : true,
"sPaginationType" : "full_numbers",
"iDisplayLength" : 50,
"oSearch": {"sSearch": '#{params[:query]}'},
"fnDrawCallback": function(oSettings) {
var curSearch = oSettings.oPreviousSearch.sSearch;
if (!prevSearch) {
prevSearch = curSearch;
} else if (curSearch != prevSearch) {
console.log("changed to: " + curSearch);
history.pushState({query: curSearch}, "title", "releases?query=" + curSearch);
prevSearch = curSearch;
}
}
});
window.addEventListener("popstate", function(e) {
if (e.state) {
table.fnFilter(e.state.query);
}
});
});
Note, I am using a rails backend and this is inlined javascript being served in the page.
you have only 2 options here:
move pushState code out of drawCallback. There must be some other code that causes the datatables to draw when user enters something. put your pushState code there. This is the ideal solution
add a hack like this
$(document).ready(function () {
var prevSearch;
var saveState = true;
var table = $('#releases').dataTable({
"bJQueryUI":true,
"sPaginationType":"full_numbers",
"iDisplayLength":50,
"oSearch":{"sSearch":'#{params[:query]}'},
"fnDrawCallback":function (oSettings) {
var curSearch = oSettings.oPreviousSearch.sSearch;
if (!prevSearch) {
prevSearch = curSearch;
} else if (curSearch != prevSearch) {
console.log("changed to: " + curSearch);
if (saveState) {
history.pushState({query:curSearch}, "title", "releases?query=" + curSearch);
}
prevSearch = curSearch;
}
}
});
window.addEventListener("popstate", function (e) {
if (e.state) {
saveState = false;
table.fnFilter(e.state.query);
saveState = true;
}
});
});

Control activates before button click

I have a custom toolbar that fires events on html button click, there is a problem with one where it's activated on init instead of after button click.. it seems to trigger the function on init.
The controls toggle correctly but it seems to be activated by default or within init.
Here is the code:
/* other Controls */
polygon: new OpenLayers.Control.Measure(
OpenLayers.Handler.Polygon, {
persist: true,
immediate: true,
handlerOptions: {
layerOptions: {
renderers: renderer,
styleMap: styleMap
}
}
}
),
choose: new OpenLayers.Control.Button({ /** **/
activateControl: false, /** Problem here **/
trigger: tochiSentaku() /** **/
})
};
var control;
for(var key in allControls) {
control = allControls[key];
control.events.on({
"measure": handleMeasurements,
"measurepartial": handleMeasurements,
"button": tochiSentaku
});
map.addControl(control);
}
function toggleControl(element){
for(key in allControls){
var control = allControls[key];
if(control.active){
control.deactivate();
}
if(element.value == key && element.click){
control.activate();
vlayer.removeAllFeatures();
var mybutton = document.getElementById('output');
var xyz = "";
mybutton.innerHTML = xyz;
}
else{
control.deactivate();
}
}
}
tochiSentaku Function
function tochiSentaku(evt){
var element = document.getElementById("attribute");
map.events.register('click', map, function(e){
vlayer.destroyFeatures(vlayer,features);
var coord = $(".olControlMousePosition").text();
$("#attribute").html('<center><img src="images/loading.gif" alt="Now Loading..." /></center>');
$.getJSON("scripts/tochi_sentaku.php",{coord:coord}, function(data){
$("#attribute").html("<button id=\"attribute_map\" onclick=\"" + data.the_geom + "\">地図</button><table id='attribute_tbl'><tr><th>項目名</th><th>値</th></tr></table>");
for(var key in data){
if(key != "the_geom"){
$("#attribute_tbl").append("<tr><td>" + key + "</td><td>" + data[key] + "</td></tr>");
}
}
$("#attribute_map").click();
});
});
}
If anyone can give me some advice would greatly appreciate it.
You haven't provided the definition of tochiSentaku in your code snippet.
But my initial guess would be, to change the code to
choose: new OpenLayers.Control.Button({
activateControl: false,
trigger: tochiSentaku
})
Figured it out. Instead of using
trigger:tochiSentaku
I used
activate:tochiSentaku
#simplyharsh Thanks for your suggestion

Categories

Resources