Change icon on click using angular-google-maps - angularjs

I have a number of markers on a map using angular-google-maps.
Can someone please tell me how to you change the icon image of a marker when you click on it?
My HTML looks like this:
<div class="map-wrapper" flex>
<ui-gmap-google-map flex center='map.center' zoom='map.zoom' class="ui-gmap-google-map" control="control">
<ui-gmap-markers models="markers" coords="'self'" icon="'icon'" doRebuildAll="true"></ui-gmap-markers>
</ui-gmap-google-map>
</div>
My controller code to populate markers:
function mapFilter(dealerList) {
angular.forEach(dealerList, function (dlr) {
if (dlr.Category_type_id == $scope.categoryType) {
var marker = {
id: dlr.Site_owner_id + "_" + dlr.Site_locationseq,
icon: "/img/dealerlocator/pin_icon.png",
events: {
click: function (marker, eventName, model, arguments) {
gotoAnchor(marker.key);
}
},
latitude: dlr.Site_address_map_latitude,
longitude: dlr.Site_address_map_longitude,
showWindow: false
};
$scope.markers.push(marker);
}
});
}
function gotoAnchor(x) {
var newHash = 'anchor_' + x;
if ($location.hash() !== newHash) {
// set the $location.hash to `newHash` and
// $anchorScroll will automatically scroll to it
$location.hash('anchor_' + x);
// Update the map marker icons
angular.forEach($scope.markers, function (mkr) {
if (mkr.id == x) {
mkr.icon = "/img/dealerlocator/pin_icon_selected.png";
} else {
mkr.icon = "/img/dealerlocator/pin_icon.png";
}
});
expandDealer(x);
} else {
// call $anchorScroll() explicitly,
// since $location.hash hasn't changed
$anchorScroll();
expandDealer(x);
}
};
In the gotoAnchor function above, you can see here that I've changed the icon in the markers, but this doesn't change on the map.

You'll need to debug your ($location.hash() !== newHash) to see if its making it through to the forEach. This plunker demo implements the method below, and the icons are updating on click;
function gotoAnchor(x) {
// Update the map marker icons
angular.forEach($scope.randomMarkers, function (mkr) {
if (mkr.id == x) {
mkr.icon = "https://mapicons.mapsmarker.com/wp-content/uploads/mapicons/shape-default/color-ffc11f/shapecolor-color/shadow-1/border-dark/symbolstyle-white/symbolshadowstyle-dark/gradient-no/cserkesz_ikon.png";
} else {
mkr.icon = 'https://mapicons.mapsmarker.com/wp-content/uploads/mapicons/shape-default/color-128e4d/shapecolor-color/shadow-1/border-dark/symbolstyle-white/symbolshadowstyle-dark/gradient-no/crow2.png';
}
});
};

Related

Flot legendFormatter is not working with ng-click

I am trying to create clickable legends. I am using flot chart and legendFormatter to manipulate the legends. Here is my code in js file:
$scope.labelFormatter = function (label, series) {
return "<div class='col-md-12' style='font-size:12px;'><span>" + label + "</span><span ng-click=\"removeFromFunnel(" + (series.data[0][0] - 1) + ")\" class=\"criteriaClose\">✖</span></div>";
};
pageData.barChartOptions.legend = {show: true, labelFormatter: $scope.labelFormatter, noColumns: index};
$scope.removeFromFunnel = function (index) {
if (index > -1) {
pageData.funnel.splice(index, 1);
}
};
This way, the program does not seem to recognize ng-click. I also tried to use onClick but I think the function needs to be out of scope with that way.
Why is ng-click not working? What should I use instead of it?
Thanks for your help.
<div style="display:none"><input type="button" value="" id="rid" ng-click="removeFromFunnel()" /></div>
<div style="display:none"><input type="hiden" value="" id="hid"/></div>
The beloow is the js code
function remove(value)
{
document.getElementById("hid").value = value;
var btn = document.getElementById("rid");
btn.click();
}
you can collect the value in the angular function removeFromFunnel()
$scope.removeFromFunnel()
{
var value = angular.element(document.querySelector('#hid'));
//do your work with the value
}

Pass md-on-demand to md-autocomplete

I would like display in md-autocomplete large list (around 50 000 records).
Autocomplete directive uses mdVirtualRepeat which provide infinity scrolling. I couldn't find way to pass md-on-demand option. Maybe someone find way to do that.
I really appreciate any help you can provide
UPDATE
I forget to share the code. I haven't problem with code performance but when list is rendering app is not responsive. In my opinion problem is in virtual rendering which still try to render whole list instead of visible part.
PS. I know $scope is bad but I'm using this example in angular-formly.
JS
$scope.to.options = [];
$scope.ctrl = {
selectedItem: null,
isDisabled: $scope.to.disabled,
noCache: $scope.to.noCache,
placeholder: $scope.to.placeholder || 'Wybierz element',
minLength: $scope.to.minLength || 0,
querySearch: querySearch,
searchTextChange: searchTextChange,
selectedItemChange: selectedItemChange,
delay: $scope.to.delay || 350,
options: []
};
if ($scope.to.dictId) {
dictionariesRepository.get($scope.to.dictId).then(function (res) {
$scope.ctrl.options = createOnDemandObject(res.Data.map(function (elem) {
return { value: elem[$scope.to.FieldVal], name: getLabel($scope.to.FieldFormula, elem) };
}));
var val;
if ((val = getValue())) {
var selected = $scope.ctrl.options.filter(function (elem) {
return elem.value == val;
})[0];
if (selected) {
$scope.ctrl.selectedItem = selected;
}
}
});
}
function createOnDemandObject(list) {
return {
list: list,
getLength: function () {
return this.list.length
},
getItemAtIndex: function (index) {
return this.list[index];
}
}
}
function searchTextChange(text) {
//$log.info('Text changed to ' + text);
}
function selectedItemChange(item) {
var getter = $parse($scope.options.key);
var setter = getter.assign;
setter($scope.model, item[$scope.to.FieldVal]);
}
function querySearch(query) {
var options = $scope.ctrl.options;
return query ? options.filter(createFilterFor(query)) : options;
}
function createFilterFor(query) {
var lowercaseQuery = angular.lowercase(query);
return function filterFn(elem) {
return (elem.name.indexOf(lowercaseQuery) === 0);
};
}
HTML
<md-autocomplete ng-disabled="ctrl.isDisabled" md-no-cache="ctrl.noCache" md-selected-item="ctrl.selectedItem" md-search-text-change="ctrl.searchTextChange(ctrl.searchText)"
md-delay="ctrl.delay"
md-search-text="ctrl.searchText" md-selected-item-change="ctrl.selectedItemChange(item)"
md-items="item in ctrl.querySearch(ctrl.searchText)"
md-on-demand
md-item-text="item.name" md-min-length="ctrl.minLength" placeholder="{{ctrl.placeholder}}">
<md-item-template>
<span md-highlight-text="ctrl.searchText" md-highlight-flags="^i">{{item.name}}</span>
</md-item-template>
<md-not-found>
Nie znaleziono pasującego wyniku dla "{{ctrl.searchText}}".
</md-not-found>
</md-autocomplete>

angular-google-maps not showing infowindow on mouseover event

I am using angularjs-google-map http://angular-ui.github.io/angular-google-maps/#!/api
I can add multiple markers with showing infoWindow by cliking on a marker, but now I need to show the marker infoWindow when the mouse enters the area of the marker icon and hide it when the mouse leaves the area of the marker icon instead of using the click event.
You can look on this example on Jsfiddle https://jsfiddle.net/meher12/bgb36q7b/ to get idea about my purpose !
My HTML code:
<ui-gmap-google-map center="map.center" zoom="map.zoom" dragging="map.dragging" bounds="map.bounds"
events="map.events" options="map.options" pan="true" control="map.control">
<ui-gmap-markers models="map.randomMarkers" coords="'self'" icon="'icon'"
doCluster="map.doClusterRandomMarkers" clusterOptions="map.clusterOptions" modelsbyref="true"
events="map.markersEvents" options="'options'"
>
<ui-gmap-windows show="'showWindow'" ng-cloak>
<div>
<p>This is an info window</p>
</div>
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
</div>
My JS code:
myApp.controller('MainController', function ($scope,uiGmapGoogleMapApi) {
$scope.numOfMarkers = 25;
uiGmapGoogleMapApi.then(function(maps) { $scope.googleVersion = maps.version; });
$scope.map = {
center: {
latitude: 45,
longitude: -73
},
zoom: 10,
options: {
streetViewControl: false,
panControl: false,
maxZoom: 20,
minZoom: 3
},
dragging: false,
bounds: {},
randomMarkers: [],
doClusterRandomMarkers: true,
currentClusterType: 'standard',
clusterOptions: {
title: 'Hi I am a Cluster!', gridSize: 60, ignoreHidden: true, minimumClusterSize: 2
}
};
$scope.map.markersEvents = {
mouseover: function (marker, eventName, model, args) {
model.options.labelContent = "Position - lat: " + model.latitude + " lon: " + model.longitude;
marker.showWindow = true;
$scope.$apply();
},
mouseout: function (marker, eventName, model, args) {
model.options.labelContent = " ";
marker.showWindow = false;
$scope.$apply();
}
};
var genRandomMarkers = function (numberOfMarkers, scope) {
var markers = [];
for (var i = 0; i < numberOfMarkers; i++) {
markers.push(createRandomMarker(i, scope.map.bounds))
}
scope.map.randomMarkers = markers;
};
var createRandomMarker = function (i, bounds, idKey) {
var lat_min = bounds.southwest.latitude,
lat_range = bounds.northeast.latitude - lat_min,
lng_min = bounds.southwest.longitude,
lng_range = bounds.northeast.longitude - lng_min;
if (idKey == null)
idKey = "id";
var latitude = lat_min + (Math.random() * lat_range);
var longitude = lng_min + (Math.random() * lng_range);
var ret = {
latitude: latitude,
longitude: longitude,
title: 'm' + i,
showWindow: false,
options: {
labelContent: ' ',
labelAnchor: "22 0",
labelClass: "marker-labels",
draggable: true
}
};
ret[idKey] = i;
return ret;
};
$scope.genRandomMarkers = function (numberOfMarkers) {
genRandomMarkers(numberOfMarkers, $scope);
};
$scope.removeMarkers = function () {
$scope.map.randomMarkers = [];
};
});
Like you see on my JS code I have created markerEvents and I can get the marker label changed on mouse events but still not showing the infoWindow attached to each marker on the map when the mouse Event is fired, despite its value is changing and take the correct value.
Someone Have an idea to resolve this issue ?
Feel free to put your changes to my Jsfiddle code :)
You must set model.showWindow instead of marker.showWindow
You can set model.show = true instead of model.showWindow, in html remove show =showWindow.

how to wrap text in angularjs and save the position

I would like to wrap text with span tag and save the position.
I know how to do it with JS but i dont know how to do it with angularjs
Here is what i have done:
http://jsfiddle.net/ymeaL06j/1/
This function gives me the position of the text in the DIV
function getSelectionPosition() {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
};
I take the start and end positions and insert them as an attribute in the span tag
After this i would like to save all the marked positions and load it later, i have a function that select text and then i can wrap it (i hope that there is a better solution)
function setSelection(savedSel) {
var charIndex = 0, range = document.createRange();
range.setStart(document.getElementById("code"), 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
You can use the same code that you illustrated above and put it inside of your angularjs controller.
Refer to my plunker code; it is a simple angularjs version of your jsfiddle code.
For example, suppose that a snippet of the index.html looks like this:
<body ng-controller="MainCtrl">
<div id="code">This is <b>some text</b> bla bla bla</div>
<br />
<input type="button" value="Mark!" ng-click="markText()" />
<input type="button" value="Remove marks!" ng-click="removeMarks()" />
</body>
Then the example angularjs controller, MainCtrl, could look like this:
app.controller('MainCtrl', function($scope) {
var getSelectionPosition = function () {
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(document.getElementById("code"));
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
}
}
$scope.markText = function() {
var currPosition = getSelectionPosition();
var selection = window.getSelection().getRangeAt(0);
var selectedText = selection.extractContents();
var span = document.createElement("span");
span.className = "Mark";
span.setAttribute("PosStart", currPosition.start);
span.setAttribute("PosEnd", currPosition.end);
span.appendChild(selectedText);
selection.insertNode(span);
};
$scope.removeMarks = function() {
$(".Mark").each(function () {
$(this).contents().unwrap();
});
};
});
Notice that the MainCtrl is the angularjs controller for the body. The ng-click on the buttons reference the markText and removeMarks functions in the controller's scope. The logic in the functions are exactly the same as you referenced in your question (and jsfiddle).
None of your JS code changed other than moving the functions inside of the controller. Again, check out the plunker above to see the actual code working.

Should $bind save child data added in an ng-repeat

Hi I have a problem with $bind, I am binding a model and outputting the models via a ng-repeat. The ng-repeat outputs the stored data and also offers some fields for adding/changing data. The changes are reflected in the scope but are not being synced to Firebase.
Is this a problem with my implementation of $bind?
The HTML:
<iframe id="fpframe" style="border: 0; width: 100%; height: 410px;" ng-if="isLoaded"></iframe>
<form>
<ul>
<li ng-repeat="asset in upload_folder" ng-class="{selected: asset.selected}">
<div class="asset-select"><input type="checkbox" name="selected" ng-model="asset.selected"></div>
<div class="asset-thumb"></div>
<div class="asset-details">
<h2>{{asset.filename}}</h2>
<p><span class="asset-filesize" ng-if="asset.size">Filesize: <strong><span ng-bind-html="asset.size | formatFilesize"></span></strong></span> <span class="asset-filetype" ng-if="asset.filetype">Filetype: <strong>{{asset.filetype}}</strong></span> <span class="asset-dimensions" ng-if="asset.width && asset.height">Dimensions: <strong>{{asset.width}}x{{asset.height}}px</strong></span> <span class="asset-type" ng-if="asset.type">Asset Type: <strong>{{asset.type}}</strong></span></p>
<label>Asset Description</label>
<textarea ng-model="asset.desc" cols="10" rows="4"></textarea>
<label>Creator</label>
<input type="text" ng-model="asset.creator" maxlength="4000">
<label>Release Date</label>
<input type="text" ng-model="asset.release">
<label for="CAT_Category">Tags</label>
<input type="text" ng-model="asset.tags" maxlength="255">
</div>
</li>
</ul>
</form>
The Controller: (fpKey is a constant that stores the Filepicker API key)
.controller('AddCtrl',
['$rootScope', '$scope', '$firebase', 'FBURL', 'fpKey', 'uploadFiles',
function($rootScope, $scope, $firebase, FBURL, fpKey, uploadFiles) {
// load filepicker.js if it isn't loaded yet, non blocking.
(function(a){if(window.filepicker){return}var b=a.createElement("script");b.type="text/javascript";b.async=!0;b.src=("https:"===a.location.protocol?"https:":"http:")+"//api.filepicker.io/v1/filepicker.js";var c=a.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c);var d={};d._queue=[];var e="pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane".split(",");var f=function(a,b){return function(){b.push([a,arguments])}};for(var g=0;g<e.length;g++){d[e[g]]=f(e[g],d._queue)}window.filepicker=d})(document);
$scope.isLoaded = false;
// Bind upload folder data to user account on firebase
var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
$scope.upload_folder = $firebase(refUploadFolder);
$scope.upload_folder.$bind($scope,'upload_folder');
// default file picker options
$scope.defaults = {
mimetype: 'image/*',
multiple: true,
container: 'fpframe'
};
// make sure filepicker script is loaded before doing anything
// i.e. $scope.isLoaded can be used to display controls when true
(function chkFP() {
if ( window.filepicker ) {
filepicker.setKey(fpKey);
$scope.isLoaded = true;
$scope.err = null;
// additional picker only options
var pickerOptions = {
services:['COMPUTER', 'FACEBOOK', 'GMAIL']
};
var storeOptions = {
location: 'S3',
container: 'imagegrid'
};
var options = $.extend( true, $scope.defaults, pickerOptions );
// launch picker dialog
filepicker.pickAndStore(options, storeOptions,
function(InkBlobs){
uploadFiles.process(InkBlobs, $scope.upload_folder);
},
function(FPError){
$scope.err = FPError.toString();
}
);
} else {
setTimeout( chkFP, 500 );
}
})();
}])
I also have a service handling the input from Filepicker, this creates new entries in the firebase at the reference that is bound (using Firebase methods rather than AngularFire maybe this breaks the binding?)
.service('uploadFiles', ['$rootScope', 'FBURL', function($rootScope, FBURL) {
return {
process: function(InkBlobs, upload_folder) {
var self = this;
var countUpload = 0;
// write each blob to firebase
angular.forEach(InkBlobs, function(value, i){
var asset = {blob: value};
// add InkBlob to firebase one it is uploaded
upload_folder.$add(asset).then( function(ref){
self.getDetails(ref);
countUpload++;
});
});
// wait for all uploads to complete before initiating next step
(function waitForUploads() {
if ( countUpload === InkBlobs.length ) {
self.createThumbs(upload_folder, { multi: true, update: false, location: 'uploads' });
} else {
setTimeout( waitForUploads, 500 );
}
})();
},
getDetails: function(ref) {
// after InkBlob is safely stored we will get additional asset data from it
ref.once('value', function(snap){
filepicker.stat(snap.val().blob, {size: true, mimetype: true, filename: true, width: true, height: true},
function(asset) {
// get asset type and filetype from mimetype
var mimetype = asset.mimetype.split('/');
asset.type = mimetype[0].replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
asset.filetype = mimetype[1];
// add metadata to asset in upload folder
ref.update(asset);
});
});
},
createThumbs: function(ref, options) {
var self = this;
// default options
options.multi = options.multi || false;
options.update = options.update || false;
options.location = options.location || 'asset';
// if pathbase is not provided generate it based on provided location
if (!options.pathbase) {
if (options.location === 'assets') {
options.pathbase = FBURL.LIBRARY + "/assets/";
} else if (options.location === 'uploads') {
options.pathbase = "/users/" + $rootScope.auth.user.uid + "/upload_folder/";
} else {
throw new Error('SERVICE uploadFiles.createThumbs: options.location is not valid must be assets or uploads');
}
}
var generateThumb = function(blob, path) {
filepicker.convert( blob,
{ width: 200, height: 150, fit: 'crop' },
{ location: 'S3', access: 'public', container: 'imagegrid', path: '/thumbs/' },
function(tnInkBlob){
var refThumbBlob = new Firebase(FBURL.FBREF).child(path);
refThumbBlob.set(tnInkBlob);
},
function(FPError){
alert(FPError);
},
function(percentage){
// can use to create progress bar
}
);
};
if (options.multi) {
// look at all assets in provided ref, if thumbnail is mission or update options is true generate new thumb
angular.forEach(ref, function(value, key){
if (typeof value !== 'function' && (!value.tnblob || options.update)) {
// thumb doesn't exist, generate it
var blob = value.blob;
var path = options.pathbase + key + '/tnblob';
generateThumb(blob, path);
}
});
} else {
// getting thumbnail for a single asset
var refAsset = new Firebase(FBURL.FBREF).child(options.pathbase + ref);
var blob = refAsset.val().blob;
var path = options.pathbase + ref + '/tnblob';
generateThumb(blob, path);
}
}
};
}]);
So to recap, data is being saved to /users/$rootScope.auth.user.uid/upload_folder and this is being rendered in the HTML. Changes in the HTML form are reflected in the scope but not in Firebase, despite the binding:
var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
$scope.upload_folder = $firebase(refUploadFolder);
$scope.upload_folder.$bind($scope,'upload_folder');
Any ideas as to why this is? Is my implementation incorrect or am I somehow breaking the binding? Is $bind even supposed to work with ng-repeat in this manner?
Thanks
Shooting myself for how simple this is, the error was in how I defined the binding. You can't set the binding on itself, you need two separate objects in the scope...
The firebase reference $scope.syncdata loads the initial data and all modifications made to $scope.upload_folder will be synced to firebase.
var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
$scope.syncdata = $firebase(refUploadFolder);
$scope.syncdata.$bind($scope,'upload_folder');

Resources