I'm trying to use Ember's Handlebars engine for a not UI related purpose. I have a series of text templates (basically placeholders + static text), like
Order number {{number}} / {{year}}
I'm using the following code in a controller function (simplified here for the sake of the example):
formattedTitle: function(order) {
var orderTitle = "Order number {{number}} / {{year}}";
var template = Handlebars.compile(orderTitle);
return template(order);
}
offer is a Ember.data record, containing both fields.
When I run the function the resulting string only contains the static text:
Order number /
It only works with the {{id}} property, probably because you can do order.id on the Ember.data record, but not order.number (you have to use get - order.get("number"))
Any idea how to solve this?
You could use the Ember's Object.getProperties() to pull multiple properties into a simple javascript object and pass that in as the Handlebars context. Not sure that this is the best way to do this, though...
formattedTitle: function() {
var order = Ember.Object.create({number: 1, year: 2013});
// retrieve the properties ahead of time using Ember getter
var orderContext = order.getProperties(['number', 'year']);
var orderTitle = "Order number {{number}} / {{year}}";
var template = Handlebars.compile(orderTitle);
var output = template(order);
return output;
}
JSBin example
Try something like this:
function formattedTitle(order) {
var number = order.get('number');
var year = order.get('year');
var orderContext = { number: number, year: year };
var orderTitle = "Order number {{number}} / {{year}}";
var template = Handlebars.compile(orderTitle);
var output = template(orderContext);
return output;
}
Related
I've been cracking my head for the last several days, trying to understand what am I doing wrong.
I'm implementing an infrastructure of lists for my app, which can include paging/infinite scroll/filtering/grouping/etc. The implementation is based on extending controllers (not array controllers, I want to be Ember 2.0 safe), with a content array property that holds the data.
I'm using Ember.computed.sort for the sorting, and it's working, but i have a strange behavior when i try to change the sorter. the sortedContent is not updating within the displayContent, even though the sortingDefinitions definitions are updated.
This causes a weird behaviour that it will only sort if I sort it twice, as if the sorting was asynchronous.
I am using Ember 1.5 (but it also happens on 1.8)
(attaching a snippet of code explaining my problem)
sortingDefinitions: function(){
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder') || 'asc';
if (_.isArray(sortBy)) {
return sortBy;
}
else {
return (sortBy ? [sortBy + ':' + sortOrder] : []);
}
}.property('sortBy', 'sortOrder'),
sortedContent: Ember.computed.sort('content', 'sortingDefinitions'),
displayContent: function() {
var that = this;
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder');
var list = (sortBy ? this.get('sortedContent') : this.get('content'));
var itemsPerPage = this.get('itemsPerPage');
var currentPage = this.get('currentPage');
var listItemModel = this.get('listItemModel');
return list.filter(function(item, index, enumerable){
return ((index >= (currentPage * itemsPerPage)) && (index < ((currentPage + 1) * itemsPerPage)));
}).map(function(item) {
var listItemModel = that.get('listItemModel');
if (listItemModel) {
return listItemModel.create(item);
}
else {
return item;
}
});
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage')
Edit:
fixed by adding another dependency to the displayContent (sortedContent.[]):
displayContent: function() {
....
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage' , 'sortedContent.[]')
Your sort function is watching the whole array sortingDefinitions instead of each element in the array. If the array changed to a string or some other variable it would update but not if an element in the array changes.
To ensure your computed property updates correctly, add a .[] to the end of the array so it looks like this: Ember.computed.sort('content', 'sortingDefinitions.[]')
I am working on Sitecore 8.1 and I am implementing filter functionality for one of the page by Sitecore lucene. Fot filtering I am using predicate builder. I have 3 multi-lists field on detail items
Product
Category
Services
Now on listing page I have all three group filters as checkboxes as given in below image -
My Requirement is I want to apply Or between inside the group like between products condition should be Or and between two groups condition should be And. For example products and Category should be And.
I followed http://getfishtank.ca/blog/building-dynamic-content-search-linq-queries-in-sitecore-7 blog post to implement this
To achieve this what I am trying -
var builder = PredicateBuilder.True<TestResultItem>();
var Categorybuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(Categorys))
{
var CategoryItems = Categorys.Split('|');
foreach (var Category in CategoryItems)
{
var ct = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(Categorys, true);
Categorybuilder = Categorybuilder.Or(i => i.Category.Contains(ct));
}
}
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(Service))
{
var ServiceItems = Service.Split('|');
foreach (var ser in ServiceItems)
{
var si = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(ser, true);
Servicebuilder = Servicebuilder.Or(i => i.Service.Contains(si));
}
}
var productsbuilder = PredicateBuilder.False<TestResultItem>();
if (!string.IsNullOrEmpty(products))
{
var productItems = products.Split('|');
foreach (var product in productItems)
{
var pd = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(product, true);
productsbuilder = productsbuilder.Or(i => i.Category.Contains(pd));
}
}
Servicebuilder = Servicebuilder.Or(Categorybuilder);
productsbuilder = productsbuilder.Or(Servicebuilder);
builder = builder.And(productsbuilder);
The above given code is not working for me. I know I am doing something wrong as I am not good with Predicate builder, Or condition is not working between check boxes group.
Can anyone please tell me where I am wrong in given code or any best way to achieve this.
Any help would be appreciated
I did something similar recently and it works like this:
Create your "or" predicates:
var tagPredicate = PredicateBuilder.False<BlogItem>();
tagPredicate = tagValues.Aggregate(tagPredicate, (current, tag) => current.Or(p => p.Tags.Contains(tag)))
where tagValues is an IEnumerable containing the normalized guids.
I do this for several guid lists. In the end I wrap them together like this:
var predicate = PredicateBuilder.True<BlogItem>();
predicate = predicate.And(tagPredicate);
predicate = predicate.And(...);
Looking at your code: first of all change
Servicebuilder = Servicebuilder.Or(Categorybuilder);
productsbuilder = productsbuilder.Or(Servicebuilder);
builder = builder.And(productsbuilder);
into
builder = builder.And(Categorybuilder);
builder = builder.And(Servicebuilder);
builder = builder.And(productsbuilder);
You need to have one main predicate to join filters with AND condition & other predicates (e.g. for categories or services or products) to join filters internally with OR condition.
// This is your main predicate builder
var builder = PredicateBuilder.True<TestResultItem>();
var Categorybuilder = PredicateBuilder.False<TestResultItem>();
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
var productsbuilder = PredicateBuilder.False<TestResultItem>();
builder = builder.And(Categorybuilder);
builder = builder.And(Servicebuilder);
builder = builder.And(productsbuilder);
Hope this will help you.
Thanks all for providing your inputs -
I updated the code as per your inputs and now it's working.
There was two changes in my old code one was builder for multilist should be inside the if statement and also adding newly created builder to main builder on same location (inside the if statement) -
I am sharing the code below so that if anyone want to use it he can easily copy from here -
var builder = PredicateBuilder.True<TestResultItem>();
if (!string.IsNullOrEmpty(Categorys))
{ var Categorybuilder = PredicateBuilder.False<TestResultItem>();
var CategoryItems = Categorys.Split('|');
foreach (var Category in CategoryItems)
{
var ct = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(Categorys, true);
Categorybuilder = Categorybuilder.Or(i => i.Category.Contains(ct));
}
builder = builder.And(Categorybuilder);
}
if (!string.IsNullOrEmpty(Service))
{
var Servicebuilder = PredicateBuilder.False<TestResultItem>();
var ServiceItems = Service.Split('|');
foreach (var ser in ServiceItems)
{
var si = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(ser, true);
Servicebuilder = Servicebuilder.Or(i => i.Service.Contains(si));
}
builder = builder.And(Servicebuilder);
}
if (!string.IsNullOrEmpty(products))
{
var productsbuilder = PredicateBuilder.False<TestResultItem>();
var productItems = products.Split('|');
foreach (var product in productItems)
{
var pd = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(product, true);
productsbuilder = productsbuilder.Or(i => i.Category.Contains(pd));
}
builder = builder.And(productsbuilder);
}
In the above code Categorys, Service and products are pipe separated values which are coming from Sitecore Multi-list field.
Thanks again everyone for help!!
I'm having a difficult time returning data from a module using RequireJS and Knockout to populate my markup for my single page app. Knockout can't seem to find my data binding observables.
I'm trying to keep each view in a separate js file, but I'm failing to identify where I've gone wrong. Here's what I have so far:
/app/app.js
define(function(require) {
require('simrou');
var $ = require('jQuery'),
ko = require('knockout'),
videoView = require('videoView');
var init = function() {
var viewModel = function() {
var self = this;
self.currentPage = ko.observable();
self.videoView = new videoView();
}
var view = new viewModel();
ko.applyBindings( view );
_router = new Simrou({
'/video/:id': [ view.videoView.getVideo ]
});
_router.start();
};
return {
init: init
};
});
/app/videoView.js
define(function(require) {
"use strict";
var $ = require('jQuery'),
ko = require('knockout');
return function() {
var self = this;
self.currentPage = ko.observable( 'showVideo' );
self.currentVideo = ko.observable();
self.videoData = ko.observableArray([]);
self.videoList = ko.observableArray([]);
var getVideo = function( event, params ) {
// ajax pseudo code
$.ajax({});
self.videoData( dataFromAjaxCall );
}
return {
getVideo: getVideo
};
};
});
index.html
When I browse to /#/video/14 I receive the following error:
Uncaught ReferenceError: Unable to parse bindings.
Bindings value: attr: { 'data-video-id': videoData().id }
Message: videoData is not defined
Here's the markup:
<section id="showVideo" data-bind="fadeVisible: currentPage()=='showVideo', with: $root">
<div class="video" data-bind="attr: { 'data-video-id': videoData().id }></div>
</section>
Like I said, I'm trying to keep each view separated, but I would love some enlightenment on what I'm doing wrong, or if this is even possible? Is there a better more efficient way?
videoData is a property of $root.videoView, not of the root model (the one you passed to applyBindings). It's also an observableArray, so videoData() is just a plain array and even if you get the context right, you won't be able to access its id property, since, being an array, it doesn't have.named properties.
In Lucene.Net, it is possible to retrieve the total number of matched documents using the TopDocs.TotalHits property.
This functionality was exposed in the Advanced Database Crawler API using an out parameter in the QueryRunner class.
What is the recommended way to retrieve the total result count using Sitecore 7's new LINQ API? It does not seem possible without enumerating the entire result set. Here is what I have so far:
var index = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>()
.Where(item => item.Content == "banana");
var totalResults = query.Count(); // Enumeration
var topTenResults = query.Take(10); // Enumeration again? this can't be right?
...
}
Try this:
using Sitecore.ContentSearch.Linq; // GetResults on IQueryable
var index = ContentSearchManager.GetIndex("sitecore_web_index");
using (var context = index.CreateSearchContext())
{
var query = context.GetQueryable<SearchResultItem>()
.Where(item => item.Content == "banana");
var results = query.GetResults();
var totalResults = results.TotalSearchResults;
var topTenResults = results.Hits.Take(10);
...
}
To get more info about sitecore and linq you can watch this session and look at this repo.
Here is my code and I can't figure out why replaceText() isn't working.
function createDoc(){
var templateid = "1jM-6Qvy47gQ45u88WfDU_RvfuSTsw27zBP_9MfsUGr8"; // get template file id
var FOLDER_NAME = "Completed Rental Agreements"; // folder name of where to put doc
// get the data from an individual user
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var data = sheet.getRange(2, 1, sheet.getLastRow()-1,sheet.getLastColumn()).getValues();
var lastRow = sheet.getLastRow();
var firstName = sheet.getRange(lastRow, 2, 1,1).getValues();
var lastName = sheet.getRange(lastRow, 3, 1,1).getValues();
var guestEmail = sheet.getRange(lastRow, 7, 1,1).getValues();
var companyEmail = "bearlakeprojectmanagement#yahoo.com";
var companyName = "Bear Lake Project Management";
var username = "jared.hislop.test#gmail.com"; // get their email (from sheet name)
var me = "jared.hislop.test#gmail.com";
//Copy Template
var docid = DocsList.getFileById(templateid).makeCopy("Rental Agreement - "+firstName+""+lastName+"-"+guestEmail).getId();
// var file = DocsList.getFileById(docid).addEditors(me);
// move file to right folder
var file = DocsList.getFileById(docid);
var folder = DocsList.getFolder(FOLDER_NAME);
file.addToFolder(folder);
var doc = DocumentApp.openById(docid);
var body = doc.getActiveSection();
var body_text = doc.addEditor("jared.hislop.test#gmail.com");
// Append Cabin Rules
// doc.appendParagraph("This is a typical paragraph.");
body.replaceText("/^companyEmail$/", "test");
body.replaceText("%companyName%", "test1");
body.replaceText("%todayDate%", "test1");
doc.saveAndClose();
}
I've tried doc.replaceText and body.replaceText along with several other options.
Any ideas why this isn't working?
Thank in advance
Consider this:
body.replaceText("%companyName%", "test1");
That will look for every instance of "companyName" with "%" on either side of it. The "%" in this case is just that, a piece of punctuation in a strange place. This is a convention used to decrease the likelihood of accidentally replacing real text in the document.
Your template document must have that exact pattern for the replacement to work. (Yours doesn't... instead you have just "companyName". Change it to "%companyName%".) Apply that rule for any other replacement you want to make.
You could benefit from some optimization.
...
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
// Next line is hard to maintain - there's a better way.
// var data = sheet.getRange(2, 1, sheet.getLastRow()-1,sheet.getLastColumn()).getValues();
// Read whole spreadsheet, skip headers
var data = sheet.getDataRange().getValues().slice(1);
// Already read in all data, use it instead of reading sheet again.
var firstName = data[data.length-1][2-1]; // (2-1) because array counts from 0
var lastName = data[data.length-1][3-1]; // while spreadsheet columns from 1
var guestEmail = data[data.length-1][7-1]; // Better: put these into variables.
...
While experimenting with your code, I ran into an autocompletion issue with doc.getActiveSection(). It turns out that there has been a recent change, according to the release notes for April 15 2013.
Renamed Document.getActiveSection() to getBody().
You should update your code accordingly.