I am using jQuery UI Sortable to sort some rows on my website.
Here is my view:
<section class="data-list">
<article id="item_<%= item.id %>" class="data sortable">
<!-- stuff goes here -->
</article>
</section>
Here is my JS:
$('.data-list').sortable({items: '> .data'}).bind('sortupdate', function() {
var release = getUrlVars()["id"];
$.ajax({
type: 'POST',
data: $(this).sortable("serialize"),
url: '/release_items/'+ release +'/prioritize'
});
});
This creates a params['item'] array that looks like this:
["1537", "1536", "1540", "1541", "1542", "1543", "1544", "1545", "1547", "1546"]
Here is my controller code:
def prioritize
#release = Release.find(params[:id])
item = #release.release_items
item.each do |i|
i.priority = params['item'].index(i.id.to_s).to_i + 1
i.save
end
end
My problem is that i have several release_items that are distinguished by an item_type column. And as it stands now i currently don't have a good way in my controller to filter by item_type in my #release = Release.find(params[:id]) line.
What i would like to do is make sure in the item.each do |i| loop that the priority is only set IF the item is in the params['item'] array. How would i do that? Please let me know if this is not clear enough. Thanks!
EDIT 1:
For every release, there are n number of release items. THose release items are separated for display on the site by their item_type column (e.g., General, Project, Data, Patch). So on the site there are 4 different lists of items and i want to be able to sort those 4 lists individually. Like i stated above, the params['item'] array being passed to the prioritize action in the controller has only the items that need to be sorted, which is want i want.
The problem i'm running in to is that the first two lines in the prioritize action will get all of the release items, not just the ones in the params['item'] array. The values in the array are the IDs of the release items that need to be sorted. Instead of getting all release items, i want to only get the items that are in the params['item'] array. I do have a ReleaseItem model as well i can select from. So, i'm trying to do this: (i know this isn't the correct code, just for clarity sake)
item = ReleaseItem.find(conditions: "id in params['item']")
Does that make a little more sense? I appreciate your help!
I think I understand what you are trying to do...
def prioritize
#release = Release.find(params[:id])
items = #release.release_items.where("id IN (?)", params['item'])
items.each_with_index do |item, index|
item.priority = index + 1
item.save
end
end
Related
I currently have an iron-list within another iron-list. The parent's data comes from a firebase-query element, and the child's data is computed from each parent item. The db structure and code looks a bit like this:
DB: [
category1: [
itemId1: {
price: 10,
title: "title"
}
]
]
<iron-list id="categoryList" items="{{categories}}" multi-selection as="category">
<template>
<div class="category-holder">
<iron-list id="{{category.$key}}" items="{{_removeExtraIndex(category)}}" as="item" selection-enabled multi-selection selected-items="{{selectedItems}}" grid>
<template>
<div class$="{{_computeItemClass(selected)}}">
<p>[[item.title]]</p>
<p>[[item.price]]</p>
</div>
</template>
</iron-list>
</div>
</template>
</iron-list>
After selecting any number of items, the user can tap on a fab to batch edit the price. This is where I'm having issues. I can't figure out how to access the correct child iron-list in order to call list.set...I'm currently trying the following very nasty method:
var categories = this.$.categoryList;
var categoryItems = categories.items;
(this.selectedItems).forEach(function(item) {
var index = item.itemId;
categoryItems.forEach(function(itemList, categoryIndex) {
if (itemList[index]) {
categories.set('item.' + categoryIndex + '.price', 10);
}
}, this);
}, this);
I'm iterating over the selected items in order to extract the item index and then iterating over the parent iron-list data (categoryItems) in order to check if the given item exists in that subset of data. If so, then I use the category index and attempt to call set on the parent iron-list using the given path to access the actual item I want to edit. As expected, this fails. Hopefully I've made myself clear enough, any help would be appreciated!
EDIT #1:
After much experimenting, I finally figured out how to correctly mutate the child iron-list:
(this.selectedItems).forEach(function(item) {
var list = this.$.categoryList.querySelector('#' + item.category);
var index = list.items.indexOf(item);
list.set(["items", index, "price"], 30);
}, this);
A couple of things worth noting. I'm using querySelector instead of the recommended this.$$(selector) because I keep running into a "function DNE" error. But now I have another problem...after calling the function, the value gets updated correctly but I get the following error:
Uncaught TypeError: inst.dispatchEvent is not a function
Here's a picture of the full error message:
I see the light, hopefully someone can help me out!
OK, I'll take a shot at this. I think the following happens, and I guess this based on how dom-repeat works:
var categories = this.$.categoryList;
var categoryItems = categories.items;
You take the variable that the iron-list is based on, but setting one array to another just creates a reference in javascript. As soon as you update categoryItems, you also update this.$.categoryList.items. When you later sets the new value, iron-list will do a dirty check and compare all subproperties, and because they are equal (because ... reference), the iron-list wont update the dom.
What you should do is to make sure it's a totally new copy and the way of doing that is to use JSON.parse(JSON.stringify(myArray)).
Further on, one major flaw I see in your code is that you're using querySelector to select an element, and then manipulate that. What you should do is to use this.categories and only that variable.
So your method should look something like:
// Get a freshly new array to manipulate
var category = JSON.parse(JSON.stringify(this.categories);
// Loop through it
category.forEach(category) {
// update your categoryList variable
}
// Update the iron list by notifying Polymer that categories has changed.
this.set('categories', category);
I want to handle a test scenario for a select menu where spec would pick a random option other than the one currently selected. I can't seem to find a working locator or method that would let me do it.
Strategy 1: get the current index of option[selected] and select random off other indices.
Strategy 2: get options not selected by.css('option:not([selected])') - get the length of the array and pick random one. This selector seems to ignore the :not part and returns total number of options.
As I am fresh to protractor, I don't really see a way to do that looking at the API. Any hint, please?
First, let's filter non-selected options using .filter():
var nonSelectedOptions = $$("option").filter(function (option) {
return option.isSelected().then(function (isSelected) {
return !isSelected;
});;
});
Now, we need a list of indexes to choose a random one from, let's use .map():
var indexes = nonSelectedOptions.map(function (option, index) {
return index;
});
Now, we need to resolve the indexes promise to get the array of indexes and use the "picking a random item from an array" solution from this answer. We are going to use .get() to get a specific option for the randomly chosen index:
indexes.then(function (indexes) {
var randomIndex = indexes[Math.floor(Math.random()*indexes.length)];
var randomOption = nonSelectedOptions.get(randomIndex);
// now select the randomOption
});
If you would use the wrapper suggested here, the option selection code would be:
randomOption.getAttribute("value").then(function (optionValue) {
mySelect.selectByValue(optionValue);
});
Not tested.
I am using in visualforce page of Salesforce.com. For demo purposes, I have used the following code snippet from the example docs shown in
http://docs.releasenotes.salesforce.com/en-us/spring14/release-notes/rn_vf_remote_objects.htm
In my code snippet i have a 'Where' clause in which i am trying to filter using 3 fields. My requirement is that the records must match the criteria A or criteria B or criteria C.
Code Example
<apex:page >
<!-- Remote Objects definition to set accessible sObjects and fields -->
<apex:remoteObjects >
<apex:remoteObjectModel name="Group_Donor__c" jsShorthand="Groupdonor"
fields="Name,Id">
<apex:remoteObjectField name="State__c" jsShorthand="State"/>
<apex:remoteObjectField name="Org_Phone__c" jsShorthand="Phone"/>
<apex:remoteObjectField name="Billing_Type__c" jsShorthand="billingtype"/>
</apex:remoteObjectModel>
</apex:remoteObjects>
<!-- JavaScript to make Remote Objects calls -->
<script>
var fetchWarehouses = function(){
// Create a new Remote Object
var wh = new SObjectModel.Groupdonor();
// Use the Remote Object to query for 10 warehouse records
wh.retrieve({
where: {
or: {
Name : {like:"%Helloworld%"}, // Error
State: {like:"%chennai%"},
//Phone: {like:"%098765432344%"},
billingtype: {like:"%Credit Card%"}
}
},
limit: 10 ,
}, function(err, records, event){
if(err) {
alert(err.message);
}
else {
var ul = document.getElementById("warehousesList");
records.forEach(function(record) {
// Build the text for a warehouse line item
var whText = record.get("Name");
whText += " -- ";
whText += record.get("Phone");
whText += " -- ";
whText += record.get("billingtype");
// Add the line item to the warehouses list
var li = document.createElement("li");
li.appendChild(document.createTextNode(whText));
ul.appendChild(li);
});
}
});
};
</script>
<h1>Retrieve Group Donors via Remote Objects</h1>
<p>Warehouses:</p>
<ul id="warehousesList">
</ul>
<button onclick="fetchWarehouses()">Retrieve Group Donors</button>
</apex:page>
When i execute this code i get the following error.
Error Message :
Invalid criteria specified for retreival. ValidationError [code=11, message=Data does not match any schemas from "oneOf" path=/where, schemaKey=null]
This issue occurs only during the following conditions.
When i use Standard field like Name in the OR condition. ( Even 2 or 1 filter)
When i use more than 3 Custom fields in the OR condition ( More than 2 Query filter)
But when i use just any 2 custom fields mentioned in the RemoteObjectModel as filters, i get the expected results.
Kindly let me know what am i missing here. If i have use more than 2 filters in or condition, how do i achieve it ? is the usage of 'OR' proper in the remote-objects?. And has anyone come across this issue. if so kindly provide me some pointers.
Thanks in advance.
I've been doing some looking and there's some bad news and some good news.
First, it's a (obscure)known limitation that you can't have more than 2 predicates for AND and OR queries - Docs here
However, you seem to have discovered another bug in that an Standard Field (Name, Id) seems to not work when used with a custom one. My workaround was to redefine ALL fields, even standard ones like this:
<apex:remoteObjectModel name="Group_Donor__c" jsShorthand="GroupDonor">
<apex:remoteObjectField name="Name" jsShorthand="NameJS"/>
<apex:remoteObjectField name="State__c" jsShorthand="State"/>
<apex:remoteObjectField name="Org_Phone__c" jsShorthand="Phone"/>
<!--.... etc-->
At least you'll be able to query standard fields this way.
As an ultimate work around, you'll probably have to retrieve two lists of records and use JavaScript to create your ultimate OR list.
Good luck!
Say I'd like to fetch only items that contains keys: "-Ju2-oZ8sJIES8_shkTv", "-Ju2-zGVMuX9tMGfySko", and "-Ju202XUwybotkDPloeo".
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T").once('value', function(snap1){
items.orderByKey().equalTo("-Ju2-zGVMuX9tMGfySko").once('value', function(snap2){
items.orderByKey().equalTo("-Ju202XUwybotkDPloeo").once('value', function(snap3){
console.log(snap1.val());
console.log(snap2.val());
console.log(snap3.val());
})
})
});
I don't feel that this is the right way to fetch the items, especially, when I have 1000 keys over to fetch from.
If possible, I really hope for something where I can give a set of array
like
var itemKeys = ["-Ju2-gVQbXNgxMlojo-T","-Ju2-zGVMuX9tMGfySko", "-Ju202XUwybotkDPloeo"];
var items = new Firebase("https://hello-cambodia.firebaseio.com/items");
items.orderByKey().equalTo(itemKeys).once('value', function(snap){
console.log(snap.val());
});
Any suggestions would be appreciated.
Thanks
Doing this:
items.orderByKey().equalTo("-Ju2-gVQbXNgxMlojo-T")
Gives exactly the same result as:
items.child("-Ju2-gVQbXNgxMlojo-T")
But the latter is not only more readable, it will also prevent the need for scanning indexes.
But what you have to answer is why want to select these three items? Is it because they all have the same status? Because they fell into a specific date range? Because the user selected them in a list? As soon as you can identify the reason for selecting these three items, you can look to convert the selection into a query. E.g.
var recentItems = ref.orderByChild("createdTimestamp")
.startAt(Date.now() - 24*60*60*1000)
.endAt(Date.now());
recentItems.on('child_added'...
This query would give you the items of the past day, if you had a field with the timestamp.
You can use Firebase child. For example,
var currFirebaseRoom = new Firebase(yourFirebaseURL)
var userRef = currFirebaseRoom.child('users');
Now you can access this child with
userRef.on('value', function(userSnapshot) {
//your code
}
You generally should not be access things using the Firebase keys. Create a child called data and put all your values there and then you can access them through that child reference.
So I have this:
var competitionModel = new Competition.CompetitionModel();
competitionModel.contest_id = this.contest_id;
this.insertView('.comp', new Competition.View({model: competitionModel}));
competitionModel.fetch();
So far so good, the Model and its (selected) values are getting display in the <div class="comp">.
Now I want to get a specific value from the same Model, in this case profile_image and it has to be the MAX value from the model. I read something about .max()-method but I dont know how to use it
I have this structure:
<div class="image"></div>
<div class="comp"></div>
1) is it possible? 2) can I use the same methods? like this.insertView('.image', blablab)
So, could anyone help me out?
Ok, judging by your comment the property is an array of things.
You cannot use the backbone max (which only applies to collections) but you can use the underscore max (they are the same thing, in the end, the former is a wrapper for the latter but let's not go into the details). You can see the collection .max() in action here.
You should be able to do something like this:
var max = _.max(competitionModel.get("property"));
Eventually you can pass a function to transform values:
var max = _.max(competitionModel.get("property"), function (element) {
// element is a single item in the list, return a number here.
});
Alternatively you can also use the underscore wrapper like this:
var max = _(competitionModel.get("property")).max(function (e) { ... });
More on max() can be found in the Underscore Docs.