I get three pending changes from oModel.getPendingChanges(), oModel is sap.ui.model.odata.v2.ODataModel
{
{
ASet('id1') : {id: 1}
},
{
BSet('id1') : {id: 1}
},
{
CSet('id1') : {id: 1}
}
}
I just want submit ASet. B and C changes is from ComboBox select. I have three ComboBoxes that are related to each other. I used binding to solve that.
<ComboBox
id="theSecondSelect"
selectionChange="onChange"
enabled="false"
showSecondaryValues="true"
value="{
path: 'propertySetId',
type: '.Utils.mandatoryValueType'}">
</ComboBox>
<items> is dynamically binding in controller.
I've even tried
for(var sBindingPath in oChanges) {
if(sBindingPath.indexOf("ASet") === -1) {
delete oModel.mChangedEntities[sBindingPath];
}
}
console.log(oModel.getPendingChanges());
I can see that pending changes has already been deleted, but the three requests still sent.
Any suggestion?
Update:
Remove pending changes by
_resetSelectChanges: function() {
var oChanges = this._oModel.getPendingChanges();
for (var sBindingPath in oChanges) {
if (sBindingPath.indexOf("ControlIoTImplementationSet") === -1) {
this._oModel.resetChanges(["/" + sBindingPath]);
}
}
}
But it will appear again after I close the form dialog.
See the API description of the resetChanges method here.
The method takes an array of strings as its parameter. Each string is a path of an entity which should be reset.
Sample call:
oModel.resetChanges(["/BSet('id1')", "/CSet('id1')"]);
This resets the changes of the two given entities. Thus only the changes to your ASet('id1') entity should be submitted.
Related
I am having some issue with removing objects in my database. I have a collection called menus which consists of several object where each object is an item in the menu. Here is how it looks :
{
"_id":ObjectId("583b7577e1206be8ee79f062"),
"restID":"583972080daa6ece0960778c",
"itemName":"buffallo chicken wings",
"subType":"Appetizers/Starters",
"cuisine":"American",
"description":"descritption of buffallo chicken wings",
"duration":"All",
"quantity":"6",
"cost":"10.95",
"__v":0
}
Now I have a X button next to each item in my frontend. The code below shows how I am trying to delete an item (when user clicks the X button) on my server side. After debugging this I observed that it is splicing the object that I want to delete but it is not updating the database. I don't understand why. Am I doing something wrong?
module.exports.removemenu = function(req, res) {
var menuId = req.body.itemId;
Menu.find({}, function(err, results){
results.map(function(menu, index){
if(menu._id == menuId) {
results.splice(index, 1);
}
menu.save();
})
res.json({res: 'success', data: results});
})
}
Are you upserting the changes to the database afterwards?
Use remove command to delete record from collection
db.restaurants.remove( { "borough": "Manhattan" } )
I'm building a friend-list managing system with Meteor.js.
For that, I have a list of users on wich I can click to invite them in my friend list.
Here is my code. I get the other user _id and profile.name respectively in the e.target.id and e.target.name.
Template.talkers.events({
"click .addTalker": function(e, tmpl){
/* Checking if there already is a pending request */
var bool = false;
for(var i = 0; i < Meteor.user().profile.friends.length; i++){
if(Meteor.user().profile.friends[i].id == id){
bool = false;
}else{
bool = true;
break;
}
}
/* If there isn't */
if(!bool){
/* I add the other user in my friend list with a pending status */
Meteor.users.update({_id: Meteor.userId()}, {
$push: {'profile.friends': {
id: e.target.id,
status: 0
}
}
});
/* Then, I add the request on the other user profile */
Meteor.users.update({_id: e.target.id}, {
$set: {'profile.friends': {
id: Meteor.userId(),
status: 2
}
}
});
/* And I create a new notification for the other user */
var notifId = Meteor.users.findOne({_id: e.target.id}).profile.notifications.length;
console.log(notifId + 1);
Meteor.users.update({_id: e.target.id}, {
$push: {'profile.notifications': {
id: (notifId + 1),
type: 1,
img: null,
link: "/profile"},
}
});
alert("An invitation has been sent to " + e.target.name)
}
}
});
}
The problem is that, if I correctly add the other user in my friend list with a pending status, I get the same error thrown two times for the two update on the other user. For the moment, I publish the _id and some informations from the profile of all users to the client. I guess the problem comes from the fact i might not be alowed to rewritte another user profile from client, but only to read it. Then, I guess I should do it server side with a method call ?
Can you confirm me the problem, or explain to me how to proceed ?
Thanks you
Yes, the lack of update permissions on other users are probably the issue here. From there, you have two options:
Use a server method to do the update for you like you said (recommended)
If you trust your users (in most cases, in my humble opinion: don't), you can allow update permissions for Meteor.users under the conditions you desire. Then you should be able to keep your update calls in the client.
i have an "back end" application which write in MongoDb (in database i have _id: with ObjectId("13f6ea...002")) i use meteor app to show information. Everything was good i displays list of information with {{#each}}. But when i wanted show one element with '_Id' nothing works.
I read this issue and adapt my code to get right root, But i can't display anything on the page. I tried to write Template helpers but it didn't helped
Db record:
{
_id: ObjectId("13f6ea...002"),
url: "foo",
title: "bar",
published: "2014-08-22 03:26:21 UTC",
image: "foo.jpg",
summary: "foo ",
categories: [
"F",
"B"
],
...
}
Route:
this.route('news', {
path: '/news/:_id',
template: 'news',
waitOn: function () {
var id = this._id;
Meteor.subscribe('news', id);
},
data: function() {
var id = this.params._id;
return News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
},
action : function () {this.render();},
});
Publish
Meteor.publish('news', function(id) {
return News.find({_id: id});
});
Template which redirect to unique post
<h4>{{title}}</h4>
And template is just {{news}}
How can i fix this?
UPDATE
My solutions to fix that:
router.js
waitOn: function () {
var id = this._id;
Meteor.subscribe('News', id);
},
data: function() {
return News.findOne(new Meteor.Collection.ObjectID(this.params._id));
},
and in template
<a href="news/{{_id._str}}">
Navigate to the appropriate url in your browser (i.e. localhost:3000/news/[_id]), open the console and enter:
Router.current().data()
That will show you the data context of the current route. Either it returns nothing, in which case there is a fundamental problem with your News.findOne query as it's returning nothing, or (more likely) it returns the required document.
In the latter case, as far as I can see there is no news property within that document, which is why it isn't rendering anything. If you change {{news}} to {{url}} or {{summary}} I would imagine it would render the requested property.
If by {{news}} you're trying to render the entire document, then (aside from the fact that it will render as something like [Object]) you need to make news a property of the object returned by your data function:
return {
news: News.findOne({ _id: Meteor.Collection.ObjectID(this.params._id)});
};
Getting Document with _id :
In the .js file under events, Say on click event and Collection EventList :-
'Submit form' : function () {
var id = this._id;
return EventList.find({_id : id}).fetch();
}
This would return the object for the id. In my Case, I am displaying a field for all documents in Collection. User selects a record and clicks Submit, which fetches all Document fields and displays to the User
I was wondering if there is a clean way in backbone to validate forms as you type without using a plugin. The issue is that if you have say a user model with: name, surname, email...
You can validate the model as a whole but not each model attribute individually.
Example:
var User = Backbone.Model.extend({
validate: function(attrs) {
if(!attrs.name) return "name not set"
}
var UserView = Backbone.View.extend({
events: { 'keyup input' : 'validateInput' },
validateInput: return this.model.isValid()
})
One generic method you can use is :
events: {
'keyup input': 'validateFeild'
},
validateFeild: function (event) {
var value = event.currentTarget.value;
var validator = $(event.currentTarget).attr('validator');
console.log(validator);
// Utils.validate(value, validator); here you can manage the validation in a separate utility class
}
and in your html have something like that :
<input id="label" type="text" validator="required" />
Here's the full example
I am using angularstrap typeahead directive. Its working fine with single object json values but its not working when replacing the json with my json object array.
Demo Json:
typeahead= ["Alabama","Alaska","Arizona","Arkansas","California","Colorado","Connecticut","Delaware","Florida","Georgia"];
<input type="text" ng-model="typeaheadValue" bs-typeahead="typeahead">
The above code is working fine.
My JSON object array:
typeahead = [
{id: 1, name: 'name1', email: 'email1#domain.com'},
{id: 2, name: 'name2', email: 'email2#domain.com'},
{id: 3, name: 'name3', email: 'email3#domain.com'}
];
$scope.typeaheadFn = function(query) {
return $.map($scope.typeahead, function(contacts) {
return contacts;
});
}
<input type="text" ng-model="typeaheadValue" bs-typeahead="typeaheadFn">
Please give me some solution for this.
You want to map your items to a list of strings, I believe.
Try:
$scope.typeaheadFn = function(query) {
return $.map($scope.typeahead, function(contact) {
return contact.name;
});
}
(I should add that I am currently stumped by something similar)
If you have, for example:
items = [
{id: 1, name: 'name1', email: 'email1#domain.com'},
{id: 2, name: 'name2', email: 'email2#domain.com'},
{id: 3, name: 'name3', email: 'email3#domain.com'}
];
You will need:
<input type="text" bs-typeahead ng-model="selectedItem" ng-options="item.name for item in items|orederBy:'name'|filter:{name:$viewValue}:optionalCompareFn"></input>
If you exclude filter from ng-options matching will be done on every property of item object, so if you want it to be done on one property add filter:{propName:$viewValue}. Also, if you exclude optionalCompareFn, default comparison from angular will be applied, but you can add your custom one (on your $scope), with signature (actual is property value of the item, stated in filter, not the whole object).
optionalCompareFn(expected,actual){ return /compare and return true or false/}
Attempt 1
I finally got this semi-working after a huge amount of frustration.
An easy way to get your desired text appearing is for each item to have a toString method.
You might have something like
typeaheadData = [
{id: 1, text: "abc", toString: function() { return "abc"; }},
{id: 2, text: "def", toString: function() { return "def"; }}
]
Then you will see the correct text in the options that popup, but the matching won't yet work properly (the items shown by the widget won't match the text the user enters in the box).
To get this working I used the new filter option that's been added in the current git version of angular-strap. Note that it's not even in the pre-built dist/angular-strap.js file in the repository, you will need to rebuild this file yourself to get the new feature. (As of commit ce4bb9de6e53cda77529bec24b76441aeaebcae6).
If your bs-typeahead widget looks like this:
<input bs-typeahead ng-options="item for item in items" filter="myFilter" ng-model="myModel" />
Then the filter myFilter is called whenever the user enters a key. It's called with two arguments, the first being the entire list you passed to the typeahead, and the second being the text entered. You can then loop over the list and return the items you want, probably by checking whether the text matches one or more of the properties of an item. So you might define the filter like this:
var myApp = angular.module('myApp', ['mgcrea.ngStrap'])
.filter('myFilter', function() {
return function(items, text) {
var a = [];
angular.forEach(items, function(item) {
// Match an item if the entered text matches its `text` property.
if (item.label.indexOf(text) >= 0) {
a.push(item);
}
});
return a;
};
});
Unfortunately this still isn't quite right; if you select an item by clicking on it, then the text parameter will be the actual object from the items list, not the text.
Attempt 2
I still found this too annoying so I made a fork of angular-strap (https://github.com/amagee/angular-strap) which lets you do this:
typeaheadData = [
{id: 1, text: "abc"},
{id: 2, text: "def"}
]
//...
$scope.myFormatter = function(id) {
if (id == null) { return; }
typeaheadData.forEach(function(d) {
if (d.id === id) {
return d.text;
}
});
};
<input bs-typeahead ng-options="item for item in items" ng-model="myModel"
key-field="id" text-field="text" formatter="myFormatter" />
With no need to fuss around with toString methods or filters. The text-field is what the user sees, and the key-field is what is written to the model.
(Nope! Still doesn't work if you update the model without going through the view).
The formatter option is needed so when you set the model value to just the key field, the widget can figure out the right text to display.