Setting repeater values from database - velo

I have this code
$w("#repeater1").forEachItem( ($item, itemData, index) => {
$item("#image2").src = reviews[count].ReviewerImage;
$item("#text17").text = reviews[count].ReviewerComment;
$item("#text28").text = reviews[count].ReviewerNickname;
$item("#ratingsDisplay1").value = reviews[count].ReviewerRating;
count++;
} );
When this runs, it updates the information in the repeater based on the information in the array reviews. The nickname, comment, and image all are being displayed correctly, but the ratings on the repeater are not updating with the rest of the data. I have tried console logging the 'reviews[count].ReviewerRating' which outputs a value of 5 for each item, but when the page loads, it the ratings display only shows 3 stars. Is there an event I need to trigger to update the reviews?

$w("#repeater1").forEachItem( ($item, itemData, index) => {
$item("#image2").src = reviews[count].ReviewerImage;
$item("#text17").text = reviews[count].ReviewerComment;
$item("#text28").text = reviews[count].ReviewerNickname;
$item("#ratingsDisplay1").rating= reviews[count].ReviewerRating;
count++;
} );
Had to set the ratings display with .rating instead of .value

Related

Modify single Item of Laravel Collection without mapping every single item

I loop trough an eloquent Collection and I want to add the data to another Collection called "$tagCollection". If an entry with the same tag_id already exists I only want to increase the rating-column for the existing entry.
At the moment it looks like this. Has anyone an Idea?
$tagCollection = collect();
$entries->each(function($entry) use($tagCollection){
$tagId = $entry->tag_id;
//something like this
if($tagCollection->contains('tag_id', $tagId)){
$tagCollection->update ('rating' => $oldRating + 0.5)
} else{
$tagCollection->push(array(
'tag_id' => $tagId,
'rating' => 0.35
));
}
});
I also tried to use ->pull() to remove the Item out of the Collection and then push it again with the new rating but I also do not know how
Can you do it with array instead of collection? For example:
$tagArray = [];
$entries->each(function ($entry) use (&$tagArray) {
if (isset($tagArray[$entry['tag_id']])) {
$tagArray[$entry['tag_id']] += 0.5;
} else {
$tagArray[$entry['tag_id']] = 0.35;
}
});
If the end goal is to update all the entries present in $entries that belong to a specific $tagId, then you can do this
$entryIds = $entries->where('tag_id',$tagId)->pluck('id')->toArray();
Entry::whereIn('id', $entryIds)->update(['rating' => \DB::raw('rating + 0.5')]);
And thats it.

Unsure what this code is doing? I want it to do the opposite of what it's actually doing

I'm working on this project that someone else already started and I'm unsure how this part of code works, it's actually doing what I don't want it to do.
Currently when I use a select multiple and press the button it adds to the array the ones that I DIDN'T select, when I want it to add the ones I did select to the array, this array is then used as the data for a table so it's obvious it's selecting the wrong stuff.
This is the method when the button is pressed. package_courses is the final array that the table data is populated with.
addCourses() {
const currentCourses = this.packageForm.package_courses.map((item) => item.course_id);
const courses = this.courses.filter((item) => {
return this.selectedCourses.indexOf(item.id) && currentCourses.indexOf(item.id) < 0
});
courses.forEach((course) => {
this.packageForm.package_courses.push({
course_id: course.id,
course: course,
price: 0
});
});
this.selectedCourses = [];
},
In the second line the filter method loops all items in this.courses and returns only those items where the statement inside returns true. indexOf is an array method that searches an array for the specified item and returns the position of the item in the array or -1 if the items isn't found. so I guess what you want to do is filter for courses where indexOf is greater or equals than/to 0, instead of less, here is your code modified.
addCourses() {
const currentCourses = this.packageForm.package_courses.map((item) => item.course_id);
const courses = this.courses.filter((item) => {
return this.selectedCourses.indexOf(item.id) && currentCourses.indexOf(item.id) >= 0
});
courses.forEach((course) => {
this.packageForm.package_courses.push({
course_id: course.id,
course: course,
price: 0
});
});
this.selectedCourses = [];
},

rxjs join and filter an observable based on values from a different observable

How do I filter an observable using values from another observable, like an inner join in SQL?
class Item {
constructor(public name: string public category: string) {
}
}
class NavItem {
constructor(public key: string public isSelected: boolean = false) {
}
}
// Build a list of items
let items = of(new Item('Test', 'Cat1'), new Item('Test2', 'Cat2'))
.pipe(toArray());
// Determine the unique categories present in all the items
let navItems = from(items)
.pipe(mergeAll(),
distinct((i:item) => i.category),
map(i=>new NavItem(i.category)),
toArray());
I'm building a faceted search so let's say that in the UI, the "Cat1" NavItem is selected, so I want to produce an observable of all the items that have that category. After filtering down to the selected NavItem, I'm not sure how to bring in the Items, filter them down and spit out only those Items that mach a selected category. Here's what I have:
let filteredItems = navItems.pipe(
mergeAll(),
filter(n => n.isSelected))
// join to items?
// emit only items that match a selected category?
Expected result would be
[{name: 'Test', category: 'Cat1'}]
If I understand correctly, you want to select a certain navItem representing a certain category and then select all the items which have such category.
If this is true, than you can consider to create a function or method such as this
selectedItems(categoryId) {
return items.pipe(filter(item => item.category === categoryId));
}
Once you click the navItem then you raise an event which references the navItem and therefore the category id you are interested. You have then to call selectedItems function and pass the category id you selected. This will return an Observable which emits all the items of the category you have selected.
I finally got back around to looking at this and I figured out how to solve this. I needed to use switchMap to join the observables together in the same context. Then I can use map to emit all relevant items:
let filteredItems = from(items)
.pipe(mergeAll(),
switchMap((i) => navItems
// Get only navItems that are selected
.pipe(filter(ni => ni.isSelected),
// Convert back to array so I can if there are any selected items
// if zero, then show all items
toArray(),
map((nav) => {
if(nav.lengh > 0) {
// If the item's category matches, return it
return nav.some(x => x.key == i.category) ? i : null;
}
// If no categories were selected, then show all
return i;
})
}),
// Filter out the irrelevant items
filter(x => x !== null),
toArray()
);

Magento- configurable products options order to match the order they are in the attribute set

I have a magento site I'm building (1.6) my site has a bunch of configurable options with 6 or so attributes set as dropdowns for the customer to pick from. After saving a configurable product the order of the attributes changes. I've been able to find what I think is happening, it is reordering them according to the attribute id not the order I have them set up in the attribute set. I need to find a way to get magento to keep the order of the attributes the same as they are in the attribute set. Any help is greatly appreciated.
Trick is pretty simple.
Just drag'n'drop them in product->edit->associatedProduct tab ;)
The order of attributes from this page is saved to catalog_product_super_attribute table.
I was also looking for the same and finally i found this and it works for me hope it will work for others too.
From Admin Panel > Catalog > Attributes > Manage Attributes select the one like if you want to make it like for the capacity 4GB > 8GB > 16GB and so on then do this small changes.
Select Manage Label / Options > Manage Options (values of your attribute) and if you already created the variables just add the position manually, like:
4GB - 1
8GB - 2
16GB - 3
Save and flush the cache.
That's it, now it should show the attributes as per the position that you assign.
It is an old question but I have found a solution right now having the same problem.
If you are still interesting in changing the order of the configurable attribute you may want to look into this method:
Mage_Catalog_Model_Product_Type_Configurable::getConfigurableAttributes()
getConfigurableAttributes() load the collection of attributes.
The first time the collection is loaded, before saving the configurable, there is no position value, so I think the attribute ID rules on the display order.
If you want to alter this order you can only add a sort for attribute_id after the ->orderByPosition() and revert the order ( this will preserve the position functionality )
For example, here I have added ->setOrder('attribute_id','DESC')
public function getConfigurableAttributes($product = null)
{
Varien_Profiler::start('CONFIGURABLE:'.__METHOD__);
if (!$this->getProduct($product)->hasData($this->_configurableAttributes)) {
$configurableAttributes = $this->getConfigurableAttributeCollection($product)
->orderByPosition()
->setOrder('attribute_id','DESC')
->load();
$this->getProduct($product)->setData($this->_configurableAttributes, $configurableAttributes);
}
Varien_Profiler::stop('CONFIGURABLE:'.__METHOD__);
return $this->getProduct($product)->getData($this->_configurableAttributes);
}
OR
In case you want to modify the order in more radical way, you can also act on this method:
Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config::getAttributesJson()
This is basically calling the getConfigurableAttributes().
To understand if this is the first configurable load, you can check all the attributes in the array $attributes to see if they all have a position ==0 and then proceed with a manual reorder )
Example
I'm omitting all the module creation and the rewrite part.
Here an example modifying getAttributesJson() in order to have the color attribute always on the top.
public function getAttributesJson()
{
$attributes = $this->_getProduct()->getTypeInstance(true)
->getConfigurableAttributesAsArray($this->_getProduct());
if (!$attributes) {
return '[]';
} else {
// == START ==
// checking if I can re-order
if ($this->isNoSavedPosition($attributes)) {
$attributes = $this->attributeReorder($attributes);
}
// == END ==
// Hide price if needed
foreach ($attributes as &$attribute) {
if (isset($attribute['values']) && is_array($attribute['values'])) {
foreach ($attribute['values'] as &$attributeValue) {
if (!$this->getCanReadPrice()) {
$attributeValue['pricing_value'] = '';
$attributeValue['is_percent'] = 0;
}
$attributeValue['can_edit_price'] = $this->getCanEditPrice();
$attributeValue['can_read_price'] = $this->getCanReadPrice();
}
}
}
}
return Mage::helper('core')->jsonEncode($attributes);
}
public function isNoSavedPosition($attributes)
{
foreach ($attributes as $attribute) {
if (isset($attribute['position']) && $attribute['position'] != 0) {
return false;
}
}
// there is no position saved
// - this is the first time the configurable is loaded
// - (the position is saved on second save action)
return true;
}
public function attributeReorder($attributes)
{
// we want the Color attribute to be always on the top
$newAttributesOrderArray = array();
foreach ($attributes as $key => $attribute) {
if (isset($attribute['label']) && $attribute['label'] == 'Color') {
$newAttributesOrderArray[] = $attribute;
unset($attributes[$key]);
}
}
$newAttributesOrderArray = array_merge($newAttributesOrderArray,$attributes);
return $newAttributesOrderArray;
}

Add a subform to a form with ajax on submit

I read this article:
http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/
That was very interesting and it works fine.
I need to do the same but with a SubForm. I mean that when a user presses a button, I call, via ajax, an action that adds, attaches and displays a subform to my existing form.
For example:
I have a form where a user must fill in the name and surname of his children, so there is a button "Add Child". When the user presses that button a SubForm should be added to my existing form and displayed. On submit it will validate exactly like the example in that article. The only difference is that in there he just adds a single field. I need to add a SubForm, but in exactly the same way.
I tried the following in my action ( called by Ajax ):
public function clonerecursivegroupAction()
{
$this->_helper->layout->disableLayout();
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('clonerecursivegroup', 'html')->initContext();
$id = $this->_getParam('id', null);
$subform1 = new Zend_Form_SubForm();
$Element1 = $subform1->createElement('text', 'text1');
$Element1->setLabel('text1')->setRequired(true);
$Element2 = $subform1->createElement('text', 'text2');
$Element2->setLabel('text2')->setRequired(false);
$subform1->addElement($Element1);
$subform1->addElement($Element2);
$this->view->field = $subform1->__toString();
}
This almost works.
The view of this action returns the html code of the SubForm, so on success of my ajax call I just display it.
The problem is that on submit it validates the form but it has lost the new subform just added. That does not happen in the article with just one element. I think I just need to add the SubForm to the existing Form, but how?
Add a prefix of the subform to the subform elements. I used the prefix "child" to represent the subforms. Each subform will be created as child1, child2 and so on.
public function clonerecursivegroupAction()
{
//.. Other code
$subform = new Zend_Form_SubForm();
$subform->setIsArray(true);
$subform->setName("child$id");
$Element1 = $subform->createElement('text', "newfield$id");
$Element1->setLabel("newfield$id")
->setRequired(true);
$subform->addElement($Element1);
$Element1 = $subform->createElement('text', "nextfield$id");
$Element1->setLabel("nextfield$id")
->setRequired(true);
$subform->addElement($Element1);
$this->view->field = $subform;
// Rest of your statements
}
Then, in the preValidation function, filter the subforms using the subform prefix, instead of the field name:
public function preValidation(array $data) {
// array_filter callback
function findForms($field) {
// return field names that include 'child'
if (strpos($field, 'child') !== false) {
return $field;
}
}
$subForms = array_filter(array_keys($data), 'findForms'); //filter the subform elements
$children = array();
foreach ($subForms as $subform) {
if (is_array($data[$subform])) {
$children[$subform] = $data[$subform];
}
}
//Iterate the children
foreach ($children as $key => $fields) { //$key = subformname, $field=array containing fiend names and values
// strip the id number off of the field name and use it to set new order
$order = ltrim($key, 'child') + 2;
$this->addNewForm($key, $fields, $order);
}
}
Add New Form function creates each of the sub forms and attaches to the main form:
public function addNewForm($form, $elements, $order) {
$subform = new Zend_Form_SubForm();
$subform->setIsArray(true);
foreach ($elements as $key => $el) {
$Element1 = $subform->createElement('text', $key);
$Element1->setLabel($form.$key)
->setValue($el)
->setRequired(true);
$subform->addElement($Element1);
}
$this->addSubForm($subform, $form, $order);
}
[EDIT] Using setIsArray for a subform creates each element of the subform as an array element. It simplifies the preValidate function. Edited the code to utilize this feature.
See the complete code in pastebin
Here is another solution using belongsTo, providing array notation to the sub form elements : http://www.stephenrhoades.com/?p=364

Resources