Im really new to all this, but Im creating a small application to which I could add items with details and update them etc with ionic, cordova and angularjs and Im struggling with following scenario:
I have the ionic views setup as so:
index.html:
<div ng-controller="mainController">
<ion-nav-view>
</ion-nav-view>
</div>
list.html:
<ion-content>
<ion-list>
<ion-item ng-repeat="item in items track by $index | filter:search" ui-sref="detailView({itemId: $index})">{{ item.name }}</ion-item>
</ion-list>
</ion-content>
add.html:
<ion-content>
<label class="item item-input">
<input type="text" ng-model="item.name" placeholder="Item title..."/>
</label>
<label class="item item-input">
<textarea cols="30" rows="10" ng-model="item.field1" placeholder="Field1..."></textarea>
</label>
<label class="item item-input">
<textarea cols="30" rows="10" ng-model="item.field2" placeholder="Field2..."></textarea>
</label>
<div class="row">
<div class="col col-33"></div>
<div class="col col-33">
<button class="button button-block" ng-click="addItem()">Add</button>
</div>
<div class="col col-33"></div>
</div>
</ion-content>
Then I have made a factory which I am just now testing and it looks like this:
factory:
.factory('itemFactory', ['$cordovaFile', '$q', function ($cordovaFile, $q) {
var itemFactory = {};
itemFactory.get = function () {
var deferred = $q.defer();
$cordovaFile.checkFile('items.json')
.then(function (result) {
$cordovaFile.readAsText('items.json')
.then(function (result) {
var parsedResult = JSON.parse(result);
deferred.resolve(parsedResult)
}, function (err) {
deferred.resolve([]);
})
}, function (err) {
switch(err.code) {
case 1:
$cordovaFile.createFile('items.json');
deferred.resolve([]);
}
});
return deferred.promise;
};
itemFactory.add = function (itemsFromScope, newItem) {
var deferred = $q.defer(),
dataToWrite;
itemsFromScope.push(newItem);
dataToWrite = JSON.stringify(itemsFromScope);
$cordovaFile.writeFile('items.json', dataToWrite, {append: false})
.then(function (result) {
deferred.resolve(itemsFromScope);
},function (err) {
console.log("Write failed");
deferred.reject(err);
});
return deferred.promise;
};
return itemFactory;
}]);
Then the mainController:
.controller('mainController', function ($scope, itemFactory) {
$scope.items = [];
itemFactory.get()
.then(function (result) {
$scope.items = result;
});
})
And then the addController:
.controller('addController', function ($scope, $location, itemFactory) {
$scope.newItem = {};
$scope.newItem.name = "";
$scope.newItem.field1 = "";
$scope.newItem.field2 = "";
$scope.addItem = function () {
itemFactory.add($scope.items, $scope.newItem)
.then(function (result) {
$scope.items = result;
});
$scope.title="";
$scope.field1="";
$scope.field2="";
$location.path('/').replace();
};
$scope.goBack = function () {
$scope.title="";
$scope.field1="";
$scope.field2="";
$location.path('/').replace()
};
})
Controllers are loaded to the views with ui-router.
Now this is all good, it might not be the optimal things, but hey, Im just trying things out. But the weird part started when I noticed that in my addController I had $scope.field1="";
etc instead of $scope.newItem.field1 = "";
. So I decided to fix them and after that fix, the adding is not working anymore. Instead of adding the right values to my $scope.items in the mainController, I get empty item on it. When I run this on iOS emulator, there is an empty row added to my listing. If I restart the emulator, the new item shows up just fine. I assume something is now refreshed in the wrong time or something, but I cannot figure out what and where. Any hints or explanations?
EDIT: Added a JS fiddle with same kinda issue to simplify: http://jsfiddle.net/9gx3tfmy/ As you can see the data is added to the array in the factory, but the ui is not updated
EDIT2: Actually, nvm, that works on the jsfiddle, but the exact same thing with ionic and it's views is not working. I stripped down the $cordovaFile parts of the code, but same thing, even on the browser. I'll check if I can update the jsfiddle into a similar state
EDIT3: Now I managed to make it work in jsfiddle, but can't try it at my project untill later today. Working fiddle here: http://jsfiddle.net/9yhryL6y/8/
If I dont add the $scope.newItem = {} to the addController, the items is added as undefined.
It looks like your input fields are bound to $scope.item
in add.html, not newItem
, so $scope.newItem
is presumably still the default empty item when you try to add it.
Try:
<label class="item item-input">
<input type="text" ng-model="newItem.name" placeholder="Item title..."/>
</label>
<label class="item item-input">
<textarea cols="30" rows="10" ng-model="newItem.field1" placeholder="Field1..."></textarea>
</label>
<label class="item item-input">
<textarea cols="30" rows="10" ng-model="newItem.field2" placeholder="Field2..."></textarea>
</label>
Also the reason the JSFiddle isn't working is because you're adding strings like "value1" to the items
array, but it is expecting an object with a name
property.
Another thing to be wary of is simply pushing the scope variable into the items
array because it is not creating a new object, you are just pushing the model the inputs are bound to into the array. Example: http://jsfiddle.net/9yhryL6y/
The ionic ToDo list demo might be useful for an example of pushing new objects into an array for ng-repeat. https://github.com/driftyco/ionic-todo/blob/master/www/js/app.js
So I finally figured out this. My problem was two things that I had misunderstood with Angular. I returned a full object from the factory and binded one part of it directly to the scope like so:
.controller('myController', ['$scope', 'myFactory', function ($scope, myFactory) {
$scope.items = myFactory.items;
})])
.factory('myFactory', function () {
var factoryItems = {};
factoryItems.items = ['item1', 'item2'];
});
now when I updated the array in my Factory, it did not update in the scope. So changed the binding to this:
$scope.myFactory = myFactory;
And then in the views used the factory like:
ng-repeat="item in myFactory.items track by $index"
This fixed the issue. This article helped me a lot:
Modified data in a factory that's bound to a controller's scope, it doesn't update