How do you update the view to a change what happens in the viewmodel code?
The app below displays a list of entries and updates the totals. It works and I can get the updated data out and into a JSON object and can update a model variable with the modified data when I click a button.
console.log(ko.toJSON(self.List()));
The view does not update on button click
<span data-bind="text: jsonList"></span>
What do I have to do to update the view? I have tried variations of the following:
self.jsonList=ko.observable(ko.toJSON(self.List()))
self.show = function(){//the button click function
self.jsonList = ko.computed(function(){
var newval = self.jsonList()
newval = ko.toJSON(self.List())
console.log(jsonList())
//newval.valueHasMutated();
return newval;
})
}
Here is the fiddle
your code was not correctly updating the observable below is a modified version of your code that update the JSON string on click, as well as an implementation of it via a computed observable (jsonList2)
the forked fiddle can be found at http://jsfiddle.net/n0jfhs8k/2/
self.show = function(){//the button click function
self.jsonList(ko.toJSON(self.List()));
}
self.jsonList2 = ko.computed(function(){
var newval = self.jsonList()
newval = ko.toJSON(self.List())
return newval;
});
Related
I am trying to build an SAPUI5 application using TreeTable and I'm facing some problems to use its methods.
In my app, I have a button which triggers this method.
onChangeViewContext: function(oEvent) {
.........
.........
var aViewContext = oContext.oModel.getProperty(sPath + "/ViewContext");
var aDataModel = oContext.oModel.getProperty("/ApplicationCollection/" + sAppId + "/DataModel");
var oStructure = this._createParentChildStructure(aDataModel);
var oTreeModel = this.getView().getModel("treeModel");
oTreeModel.setData(oStructure);
this._oViewDetailLine = oSource.getParent().getParent().getParent();
this._oViewDetailLine.setVisible(false);
this.byId("idSelectElementsPanel").setVisible(true);
this._setSelectedItems(aViewContext, oTree);
}
What I'm trying to do here is only bind the rows with my treeModel, get tree table object and send it to my _setSelectedItems method which below.
_setSelectedItems: function(aViewContext, oTree) {
oTree.clearSelection();
var sElementName;
var aSelectedIndices = [];
var aElements = [];
var aRows = oTree.getRows();
aRows.forEach(function(row) {
if (row._oNodeState !== undefined) {
aElements.push(row.getCells()[0].getText());
}
});
I need to get rows array here because I will use it for setting selected items of tree table. The problem is when "onChangeViewContext" triggered, oTable.getRows() returns an empty array. But when I click cancel button (which just hides my tree table, nothing more) and then trigger "onChangeViewContext" function again, I can get the rows array completely.
Even on the first call when I try to get table's model, I can get the treeModel and its data correctly.
I've tried to refresh bindings, aggregations etc. But no luck.
By the way, I'm using row binding in my xml view like this :
<t:TreeTable id="idSelectElementsTree" rows="{path: 'treeModel>/'}" selectionMode="MultiToggle" enableSelectAll="false"
rowSelectionChange="onSelectElement">
I'm really drowning here so any any help would be appreciated.
Edit : rest of the setSelectedIndexes function :
aViewContext.forEach(function(name) {
sElementName = name;
if (aElements.indexOf(sElementName) !== -1) {
aSelectedIndices.push(aElements.indexOf(sElementName));
}
});
aSelectedIndices.forEach(function(idx) {
if (oTree.getRows()[idx]._bHasChildren) {
oTree.expand(idx);
}
oTree.addSelectionInterval(idx, idx);
});
What could help here is to add an event rowsUpdated="onRowsUpdated" to the table in the XML view. This event is triggered after the table has been loaded and will hence provide you with the data via;
this.getView().byId("sTableId").getRows();
The difference to your approach is that the event would not be triggered by the press of a button but automatically, as the table is rendered. You can then also use this function to trigger another one as per your use case.
I'm quite new to AngularJS and had to takeover somebody else's project at work which has little to no documentation.
I have 2 kinds of check-boxes in my application, one is a "Select All" checkbox and another is a device selection checkbox. As the name suggests, the select all will select all the devices listed below it and if I uncheck the "select all" checkbox, I can check the devices individually to see them.
Here is the code of the Select all checkbox -
<input type="checkbox" data-ng-model='devCtrl.uiChoices.selectAll' value='true' data-ng-change="devCtrl.selectAll()"/><h4>Select / Deselect All</h4>
Controller:
_this.uiChoices.selectAll = true;
I can understand from above that by default, select all is checked and I can see all the devices below it checked too.
Moving onto the device check-box -
<input type="checkbox" data-ng-model='device.draw' data-ng-change="device = devCtrl.adjustVisibility(device)" />
Controller -
_this.adjustVisibility = function(draw) {
draw.marker.setVisible(draw.plot);
return draw;
}
Basically, whenvever the device is selected, it will appear on a google map. If it is unchecked, it won't appear on the map.
My question is, after I uncheck the "Select all" checkbox and then select only 2 devices in the list below and then do a page refresh, I want the select all to be disabled and show only those 2 devices to be checked and displayed on the map.
The list of devices is being pulled from a MySQL database and is updated dynamically.
Any help is appreciated.
As I said, you can do it by 3 different ways.
1 - Using $scope variable
In AngularJS you have a main Controller usually set at index.HTML body that you can access from all other controllers. You could use it to store your data on the $scope variable. See the example:
index.html:
<body ng-controller="DefaultController">
DefaultController.js:
angular.module('YourModule').controller('DefaultController', ['$scope', function ($scope) {
//Storing Your data
$scope.isChecked = true;
}]);
YourCheckBoxController.js
angular.module('YourModule').controller('YourCheckBoxController', ['$scope', function ($scope) {
//Here you gonna access the $scope variable, that does not change on page reload
$scope.accessingTheVariable= function () {
if ($scope.isChecked) {
//Select All
}
else {
//Do not Select All
}
};
$scope.onCheckBoxToggle {
$scope.isChecked = _this.uiChoices.selectAll;
//More code
};
}]);
2- Using localStorage
//The property exists
if (localStorage.hasOwnProperty("isChecked")) {
if(localStorage.isChecked) {
//Select All
}
else {
//Do not Select All
}
}
//To set localStorage.isChecked
localStorage.setItem("isChecked", _this.uiChoices.selectAll);
3 - Angular Service (Factory)
On this scenario you should create a service that could be accessed from every Controller in your project (usefull if you gonna use the data on more than 1 Controller). Look:
YourService.js
angular.module('YouModule').factory('YouService', function () {
var data =
{
IsChecked = true
};
data.buildIsChecked = function (isChecked) {
this.IsChecked = isChecked;
};
return data;
});
YourIsCheckedController.js:
angular.module('YourModule').controller('YourCheckBoxController',
['$scope', 'YouService', function ($scope, YouService) {
//Setting the service
//...
YouService.buildIsChecked(_this.uiChoices.selectAll);
//Accessing the service Information (it could be accessed from any Controller, just remember to set Service Name at begin of the module declaration)
var isChecked = MenuService.IsChecked;
}]);
You need a way of saving those checked devices.
Try localStorage. Basically, when you select a device, add it to an array, like checkedDevices and add this array to localStorage like so:
localStorage.setItem("devices", JSON.stringify(checkedDevices));
then, at the beginning of your controller, get this array from the localStorage:
var devices = JSON.parse(localStorage.getItem("devices"));
then, check if it has items, if it does, set selectAll to false:
if (devices.length > 0){
this.selectAll = false;
}else{
this.selectAll = true;
}
then, for every device, check if it is in devices array, if it is, select it.
I have an app in AngularJS. There I have a table and it has 5 columns.
first three columns contain text fields where user can fill the data and next two columns contain a submit and reset button.
On the press event of the reset button I want to reset all the three models associated with the text fields.
Please suggest.
Change the reset function to use angular.copy
$scope.reset = function () {
$scope.datas = angular.copy($scope.initial);
};
If your object is like
$scope.data = { column1:"asas", column2:"asas", column3:"asadas" };
You can don it in 2 way
1.<button ng-click="data = {};"></button>
2.<button ng-click="reset();"></button>
$scope.reset = function(){
delete $scope.data;
}
I'm now developing website and there has edit note field features in ng-repeat. To edit note field, user need to click link to display form first then key-in into it and then save it as follow. Problem is i cannot hide that input after successfully saved. Coding is as follow.
index.jade
tr(data-ng-repeat="application in job.applications")
td.notes
div.bold #{getMessage('Notes:')}
div.normal
div(ng-hide='showDetails')
{{application.note}}
.br
a.admin_edit_gray(href='#', ng-click="showDetails = ! showDetails") Edit Note
div(ng-show='showDetails')
textarea.form-control.small-text-font(ng-model='editableTitle', ng-show='showDetails', maxlength="100", ng-trim="false")
div.editable
div(ng-if="editableTitle.length == 100")
| #{getMessage('max 100 symbols.')}
a.small-text-editButton(href='#', ng-click='save(application, editableTitle, application.id)') Save
| |
a.small-text-cancelButton(href='#', ng-click="showDetails = ! showDetails") close
controller.js
$scope.showDetails = false;
$scope.noteFormData = {};
$scope.save = function(application, editableTitle, appId) {
$scope.noteFormData = {
appId: appId,
note: editableTitle
};
mytestService.writeNote($scope.noteFormData).then(
function (notemessage) {
application.note = notemessage;
alert('Note is successfully saved.');
$scope.showDetails = false;
}
);
};
I've tried to hide form as $scope.showDetails = false; after successfully saved. But it does not work at all. Please help me how to solve that issue.
You are creating showDetails inside the $scope of the ngRepeat. Each iteration of the loop creates a new child $scope of the controller's $scope.
In this way, just set $scope.showDetails from the controller will not work.
In order to fix that you need to get the reference to the object that is being iterated and set the show details:
Instead of:
ng-click="showDetails=!showDetails"
Use:
ng-click="application.showDetails=!application.showDetails"
After that, when submiting, you can choose which one you would like to show or hide by using the correct reference or by iterating over all itens of the array and setting showDetails to false.
Instead of:
$scope.showDetails = false;
Use:
application.showDetails = false;
set a variable in controller and set its value false .After your save() function is executed successfully set that variable to true. And in the view page put an condition of ng-show on tr if that value that is true.
I have an Angular single page app with a kendo grid that is bound to a RESTful API. When this data is updated externally, I have a web socket (PubNub) function I am triggering with the intent to refresh and display externally changed data while preserving the hierarchy of the grid as well as selected row.
I can get the data grid to refresh but this doesn't refresh the datasource with the changed data from the API. If I include a dataSource.read(), then it seems to prevent my persistence of the hierarchy, IE it closes previously opened hierarchical grids.
I have an tried to use the example from the Telerik Docs for this listed here: Persist expanded rows after refresh
vm.savestate = function(e) {
console.log('save pressed:');
var grid = $scope.responseGrid;
var expanded = $.map(grid.tbody.children(":has(> .k-hierarchy-cell .k-minus)"), function(row) {
console.log(row);
console.log($(row).data("uid"));
return $(row).data("uid");
});
grid.one("dataBound", function() {
grid.expandRow(grid.tbody.children().filter(function(idx, row) {
return $.inArray($(row).data("uid"), expanded) >= 0;
}));
});
grid.refresh();
};
The solution was rather simple actually. You can't use the uid as this is generated upon each new read for the observable array. The correct choice is to use a model id as the below example:
vm.savestate = function(e) {
console.log('save pressed:');
var grid = $scope.responseGrid;
var expanded = $.map(grid.tbody.children(":has(> .k-hierarchy-cell .k-minus)"), function(row) {
console.log(row);
console.log($(row).data("uid"));
return grid.dataItem($(row)).EmployeeID; //Use Model Data instead of uid
});
grid.one("dataBound", function() {
grid.expandRow(grid.tbody.children().filter(function(idx, row) {
return $.inArray(grid.dataItem($(row)).EmployeeID, expanded) >= 0;//Use Model Data instead of uid
}));
});
grid.refresh();
};
Thanks to the Telerik support team for this response. Here is their updated example on how to persist expanded rows after a refresh of a Kendo-UI Grid when a dataSource.read() is required.