I'm using cellClass in ui.grid to add the class of tomato.
cellClass: function(grid, row, col) {
if (grid.getCellValue(row,col) === 'confirmed') {
return 'green';
}
else {
return '';
}
}
},
How can I remove this class? I'm trying but I don't see a way to find the element with the green class so I can remove it.
$scope.confirm = function(rowEntity) {
confirmService.sendResponse(payload, idPart)
.success(function(result) {
if (rowEntity.entity.status.status !== "confirmed") {
remove 'green';
}
console.log('success ', result);
})
.error(function(error) {
console.log('failed ', error);
});
};
You shouldn't need to remove it, you need to update the status in the grid to something other than confirmed (perhaps 'saved'), and then call notifyDataChange to tell the grid that you've changed a data value, the grid will then re-evaluate the cell classes.
The notifyDataChange api is used in http://ui-grid.info/docs/#/tutorial/113_adding_and_removing_columns, amongst other tutorials, and I think the value you want is uiGridConstants.dataChange.EDIT.
Related
I'm creating this text editor, with the field of name, and address
<ckeditor :editor="editor" v-model="data[index].name">
<ckeditor :editor="editor" v-model="data[index].address.1">
<ckeditor :editor="editor" v-model="data[index].address.2">
and the data property
data() {
return {
data:[],
index:0,
editor: customedit
};
},
the editor also have two button, next and back, with the method add and substracting "index".
the data, is loaded before mount from server, with structure like this
serverdata = [{name:'name1',address:{1:'address 1',2:'address 2'}} , {name:'name2',address:{1:'address 4',2:'address 4'}}]
so what I want to do is, after data from server is loaded, user can move between data, and when user make change to it, the data index that user make change to will be logged.
so far I have been using deep watcher like this:
watch: {
data: {
handler(val) {
console.log('the data is changed');
console.log(this.index + 1);
},
deep: true
}
},
but even when there are no change, when I click next, the log is shown,
thanks for any help/suggestion
Maybe you may compare new and old value if they are different do the console.log.
You can receive two parameters in the function something like this:
handler(newValue, oldValue) {
if(newValue !== oldValue) {
console.log('the data is changed');
console.log(this.index + 1);
}
},
deep: true
You can compare the content in the array with:
if(JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
console.log('the data is changed');
console.log(this.index + 1);
}
},
deep: true
Okay your problems seems you are receiving the same values in old and new values. You can try to watch a computed property and use that to convert array into string.Even with that string you can reconstruct the old array. I try to do a example:
data() {
return {
yourArray: []
}
},
computed: {
yourArrayStr: function () {
return JSON.stringify(this.yourArray)
}
},
watch: {
yourArrayStr: function(newValue, oldValue) {
if(newValue !== oldValue){
let oldValueArray = JSON.parse(oldValue);
console.log();
console.log();
}
},
}
I have a long set of checkboxes. I would like two groups of three of them to behave as radio buttons. Now, leaving aside my UX choices, how can I make this work?
The checkboxes are implemented as properties on a single object, layer:
data() {
return {
layer: {},
}
},
watch: {
layer: {
handler(val, oldval) {
mapping.updateLayers(val)
},
deep: true,
},
},
That works fine. But intercepting val and updating this.layer inside handler() doesn't:
handler: function(val, oldval) {
if (val.FutureYear) { this.layer.NextYear = false; this.layer.ExistingYear = false; }
if (val.ExistingYear) { this.layer.NextYear = false; this.layer.FutureYear = false; }
if (val.NextYear) { this.layer.ExistingYear = false; this.layer.FutureYear = false; }
mapping.updateFoiLayers(val);
},
How can I achieve this result? (I'd prefer not to have to implement actual radio buttons because that makes managing all the layers and UI more complex.)
Example: https://codepen.io/jacobgoh101/pen/NyRJLW?editors=0010
The main problem is the logic in watch.
If FutureYear is selected already, other field becomes unchangeable. Because if (val.FutureYear) is always the first one being triggered and the other 2 field will always be set to false immediately.
Another thing about watch is that it will be triggered when
user changed the value
program changed the value (this is unnecessary and make things harder to handle)
Therefore, handling #change event is more appropriate in this scenario.
JS
methods: {
handleChange: function(e) {
const name = e.target.name;
if (this.layer[name]) {
Object.keys(this.layer).map((key)=>{
if(key != name) {
this.layer[key] = false;
}
})
}
}
}
html
<div id="app">
<input type="checkbox"/ v-model="layer.FutureYear" name="FutureYear" #change="handleChange($event)">FutureYear<br/>
<input type="checkbox"/ v-model="layer.NextYear" name="NextYear" #change="handleChange($event)">NextYear<br/>
<input type="checkbox"/ v-model="layer.ExistingYear" name="ExistingYear" #change="handleChange($event)">ExistingYear<br/>
</div>
I'm trying to populate Angularjs UI grid, when geocoder.geocode of google map executes, the UI grid populated..but nothing its appears ine the navigator until i click something on the DOM then the data appears in the UI grid..why it behaves like that???
geocoder.geocode({'location': latlng}, function(results, status) {
//console.log("vb");
$scope.cp++;
if (status === google.maps.GeocoderStatus.OK) {
if (results[1]) {
console.log('azerty: ' + JSON.stringify($scope.aqw[index]) );
$scope.aqw[index].adress=results[1].formatted_address;
if($scope.cp == $scope.Mylength){
//alert(JSON.stringify($scope.aqw));
$scope.gridOptions.data=$scope.aqw;
}
map.setZoom(11);
var marker = new google.maps.Marker({
position: latlng,
map: map
});
//console.log("vbbbb");
$scope.varr=results[1].formatted_address;
infowindow.setContent(results[1].formatted_address);
infowindow.open(map, marker);
//alert("kl");
} else {
window.alert('No results found');
}
} else {
window.alert('Geocoder failed due to: ' + status);
}
$scope.titi="djdjd";
// console.log( $scope.varr+' '+'cccccccccccccccccccccccccccccc');
console.log('azertym: ' + JSON.stringify($scope.aqw[index]) );
$scope.myData={};
$scope.myData+=$scope.aqw[index];
console.log('yoyoyoyo: ' + JSON.stringify($scope.aqw));
});
Im assuming it is because of the digest cycle, the scope isn't aware of the changes and there for it is not updating the dom.
you can include a $scope.$apply() at the end of the callback function. and this will fix the issue...
read more about digest and apply here: https://docs.angularjs.org/api/ng/type/$rootScope.Scope
I try to use jstree control in my TypeScript code for an angularjs application. I use jstree typings and jstree.directive to show a tree. Everything works to the point when I need to handle menu item click and call for the base method. Inside of my action there is no "this" (contextmenu) scope. Any suggestions?
class MapTreeViewController {
mapTreeView: JSTree;
vm.mapTreeView = $('#jstree').jstree(
{
'core': { 'data': items },
'plugins': ['themes', 'ui', 'contextmenu'],
'contextmenu': {
'items': function(node:any) {
var vmNode = this;
return {
'rename': { // rename menu item
'label': 'Rename',
'action': function(obj) {
this.rename(obj);
}
}
};
}
}
});
}
Somewhere inside of a method.
this is not an instance - take a look at the original function to see how to obtain an instance:
https://github.com/vakata/jstree/blob/master/src/jstree.contextmenu.js#L84
"action" : function (data) {
var inst = $.jstree.reference(data.reference),
...
I been trying to do checkbox Checkall and UnCheckall using subscribe and i'm partially successful doing that but i am unable to find a fix in couple of scenarios when i am dealing with subscribe .
Using subscribe :
I am here able to checkAll uncheckAll but when i uncheck a child checkbox i.e test1 or test2 i need my parent checkbox name also to be unchecked and in next turn if i check test1 the parent checkbox should be checked i.e keeping condition both child checkboxes are checked .
For fiddle : Click Here
ViewModel :
self.selectedAllBox.subscribe(function (newValue) {
if (newValue == true) {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(true);
});
} else {
ko.utils.arrayForEach(self.People(), function (item) {
item.sel(false);
});
}
});
The same scenario can be done perfectly in easy way using computed but due some performance issues i need to use subscribe which is best way it wont fire like computed onload .
Reference : Using computed same thing is done perfectly check this Fiddle
I tried to use change event in individual checkbox binding but its a dead end till now.
Any help is appreciated .
Your subscription only applies to edits on the selectedAllBox. To do what you want, you'll need subscriptions on every Person checkbox as well, to check for the right conditions and uncheck the selectedAllBox in the right situations there.
It strikes me as odd that this would be acceptable but using computed() is not. Maybe you should reconsider that part of your answer. I would much rather compute a "isAllSelected" value based on my viewModel state, then bind the selectedAllBox to that.
I solved a similar problem in my own application a couple of years ago using manual subscriptions. Although the computed observable method is concise and easy to understand, it suffers from poor performance when there's a large number of items. Hopefully the code below speaks for itself:
function unsetCount(array, propName) {
// When an item is added to the array, set up a manual subscription
function addItem(item) {
var previousValue = !!item[propName]();
item[propName]._unsetSubscription = item[propName].subscribe(function (latestValue) {
latestValue = !!latestValue;
if (latestValue !== previousValue) {
previousValue = latestValue;
unsetCount(unsetCount() + (latestValue ? -1 : 1));
}
});
return previousValue;
}
// When an item is removed from the array, dispose the subscription
function removeItem(item) {
item[propName]._unsetSubscription.dispose();
return !!item[propName]();
}
// Initialize
var tempUnsetCount = 0;
ko.utils.arrayForEach(array(), function (item) {
if (!addItem(item)) {
tempUnsetCount++;
}
});
var unsetCount = ko.observable(tempUnsetCount);
// Subscribe to array changes
array.subscribe(function (changes) {
var tempUnsetCount = unsetCount();
ko.utils.arrayForEach(changes, function (change) {
if (change.moved === undefined) {
if (change.status === 'added') {
if (!addItem(change.value))
tempUnsetCount++;
} else {
if (!removeItem(change.value))
tempUnsetCount--;
}
}
});
unsetCount(tempUnsetCount);
}, null, 'arrayChange');
return unsetCount;
}
You'll still use a computed observable in your viewmodel for the the select-all value, but now it'll only need to check the unselected count:
self.unselectedPeopleCount = unsetCount(self.People, 'Selected');
self.SelectAll = ko.pureComputed({
read: function() {
return self.People().length && self.unselectedPeopleCount() === 0;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:0});
Example: http://jsfiddle.net/mbest/dwnv81j0/
The computed approach is the right way to do this. You can improve some performance issues by using pureComputed and by using rateLimit. Both require more recent versions of Knockout than the 2.2.1 used in your example (3.2 and 3.1, respectively).
self.SelectAll = ko.pureComputed({
read: function() {
var item = ko.utils.arrayFirst(self.People(), function(item) {
return !item.Selected();
});
return item == null;
},
write: function(value) {
ko.utils.arrayForEach(self.People(), function (person) {
person.Selected(value);
});
}
}).extend({rateLimit:1});
http://jsfiddle.net/mbest/AneL9/98/