I am trying very hard to make my cascading select decorate using telerik form decorator. Here is my js,
var attributes = s.attributes;
for (var i = 0, iLen = attributes.length; i < iLen ; i++) {
$elem.append('<option ' + (selectedValue === attributes[i].id ? 'selected ' : '') + 'value="' + attributes[i].id + '">' + attributes[i].name + '</option>');
}
after this I am calling,
formDecorator.decorate($elem[0], false);
It only works first time when the parent select changed(in a cascading select). But after this nothing works. I have tried,
formDecorator.decorate();
and
formDecorator.updateSelect($elem[0]);
Is there is any way to make it work?
A quick search in Telerik's forums gave me this thread that seems to have a useful response: http://www.telerik.com/community/forums/aspnet-ajax/form-decorator/cascading-select-in-javascrip-and-telerik-radformdecorator.aspx. I would give it a try and post there for more people to see. I hope it helps you.
Related
Sorry in advance, as I have only been working with C# for about a month with limited history in VB years ago. It's a Mail merge kind of loop that I am trying to create for work to make their life easier. I have the dates figured out. I have a NumUpDown control setting the int myInt, and a formCount int starting at 0.
The code worked fine when I used if(formCount==0), when I switched it to
for(formCount=0;formCount<myInt;formCount++)
it now throws a
"System.NullReferenceException: 'Object reference not set to an
instance of an object.'"
I know there is probably another way to do what I am working on which is to just add sequential dates to forms a month at a time. I have the dates stored in an array myDate[31].
I am using the numUpDwn(min 1 max 31) to get myInt so we can select how many days in the month, or only print a couple days if we need to replace pages, so we can print anywhere from 1 to 31 pages.
With the if statement it would create the first page from the template (.dotx) to doc(var) copy the contents of doc to doc2 and add a new page to receive the next content paste.
I am sure this is a silly question, that someone will have a simple answer too. The loop is supposed to open the template, add the date, copy to doc2. close the original, and restart until it reached the number of pages/dates selected. Thanks for any help, this is the last section I need to finish and I am stumped. Oh, and I used the != because it was skipping the merge field, but with only 1 field not equal to anything worked.
private void BtnPrint_Click(object sender, EventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
var doc = new Microsoft.Office.Interop.Word.Document();
var doc2 = new Microsoft.Office.Interop.Word.Document();
//app.Visible = true;
doc = null;
doc2.PageSetup.Orientation = WdOrientation.wdOrientLandscape;
doc2.PageSetup.TopMargin = app.InchesToPoints(0.6f);
doc2.PageSetup.BottomMargin = app.InchesToPoints(0.17f);
doc2.PageSetup.LeftMargin = app.InchesToPoints(0.5f);
doc2.PageSetup.RightMargin = app.InchesToPoints(0.5f);
String fileSave;
fileSave = ("OTSU" + "_" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
int formCount;
//formCount = 0;
var filepath = System.Windows.Forms.Application.StartupPath + outfile;
doc = app.Documents.Add(filepath);
doc2.Activate();
//OBJECT OF MISSING "NULL VALUE"
Object oMissing = System.Reflection.Missing.Value;
for (formCount = 0; formCount<myInt;formCount++)
{
doc.Activate();
foreach (Microsoft.Office.Interop.Word.Field field in doc.Fields)
{
Range rngFieldCode = field.Code;
String fieldText = rngFieldCode.Text;
// ONLY GETTING THE MAILMERGE FIELDS
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11);
// GIVES THE FIELDNAMES AS THE USER HAD ENTERED IN .dotx FILE
fieldName = fieldName.Trim();
if (fieldName != "M_2nd__3rd")
{
field.Select();
app.Selection.TypeText(myDate[formCount].ToShortDateString());
}
formCount++;
Microsoft.Office.Interop.Word.Range dRange = doc.Content;
dRange.Copy();
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).PasteSpecial(DataType: Microsoft.Office.Interop.Word.WdPasteOptions.wdKeepSourceFormatting);
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).InsertBreak(Microsoft.Office.Interop.Word.WdBreakType.wdPageBreak);
Clipboard.Clear();
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
}
}
}
doc2.SaveAs2("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
app.Documents.Open("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
doc2.Close(WdSaveOptions.wdDoNotSaveChanges);
I haven’t run your code, but as far as I can see, this code would probably fail even without the formcount loop in the situation where you have more than one MERGEFIELD field because you close doc As soon as you have processed such a field, and yet the foreach loop is processing each Field in doc.Fields.
Even if that foreach loop terminates gracefully, in the next iteration of the formCount loop you are using doc.Activate(), but doc has closed so that will fail.
So I suggest that the main thing to do is consider which documents need to be open at which point for the process to work.
Some observations (not necessarily to do with your primary question)
where is myInt set?
is having a formCount++ loop and using formCount++ within the loop for every MERGEFIELD in doc Really your intention?
you might be better off testing field.Type() when filtering MAILMERGE fields rather than matching the text, at least if such fields can be set up by end users
when you process collections in Word and you are either adding or deleting members of the collection, you sometimes have to consider using a loop that starts with last member of the collection and works back towards the beginning. Not sure you need to do that in this case but since you may be “deleting” when you do your field.Select then Typetext, please bear that in mind
It may seem like a complication when you are mainly trying to sketch out the logic of your loops, but I generally find it very helpful to start using try...catch...finally blocks sooner rather than later during development.
I did find a solution for now. Since there is only one MERGFIELD, instead of trying to open doc, insert date, copy to new doc2, close doc, repeat I found I can open, insert date, copy to new doc2, undo edit on doc and repeat. At least it works for now, and I can get back to the books and learn some more while I map out the big project I have planned. I am sure I will be on here a bit with more questions. Without #slightly-snarky asking the questions he did, I wouldn't have thought of this so I have to give them credit for the answer. I did have to put the doc.Undo(); at the top of the loop and it will only work with one field. But its a start.
private void BtnPrint_Click(object sender, EventArgs e)
{
var app = new Microsoft.Office.Interop.Word.Application();
String fileSave;
fileSave = ("OTSU" + "_" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
int formCount;
formCount = 0;
var filepath = System.Windows.Forms.Application.StartupPath + outfile;
var doc = new Microsoft.Office.Interop.Word.Document();
doc = app.Documents.Add(filepath);
app.Visible = true;
doc.Activate();
var doc2 = new Microsoft.Office.Interop.Word.Document();
doc2.PageSetup.Orientation = WdOrientation.wdOrientLandscape;
doc2.PageSetup.TopMargin = app.InchesToPoints(0.6f);
doc2.PageSetup.BottomMargin = app.InchesToPoints(0.17f);
doc2.PageSetup.LeftMargin = app.InchesToPoints(0.5f);
doc2.PageSetup.RightMargin = app.InchesToPoints(0.5f);
doc2.Activate();
//OBJECT OF MISSING "NULL VALUE"
Object oMissing = System.Reflection.Missing.Value;
for (formCount = 0; formCount < myInt; formCount++)
{
doc.Undo();
foreach (Microsoft.Office.Interop.Word.Field field in doc.Fields)
{
Range rngFieldCode = field.Code;
String fieldText = rngFieldCode.Text;
// ONLY GETTING THE MAILMERGE FIELDS
if (fieldText.StartsWith(" MERGEFIELD"))
{
Int32 endMerge = fieldText.IndexOf("\\");
Int32 fieldNameLength = fieldText.Length - endMerge;
String fieldName = fieldText.Substring(11);
// GIVES THE FIELDNAMES AS THE USER HAD ENTERED IN .dotx FILE
fieldName = fieldName.Trim();
if (fieldName != "M_2nd__3rd")
{
field.Select();
app.Selection.TypeText(myDate[formCount].ToShortDateString());
}
Microsoft.Office.Interop.Word.Range dRange = doc.Content;
dRange.Copy();
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).PasteSpecial(DataType: Microsoft.Office.Interop.Word.WdPasteOptions.wdKeepSourceFormatting);
doc2.Range(doc2.Content.End - 1, doc2.Content.End - 1).InsertBreak(Microsoft.Office.Interop.Word.WdBreakType.wdPageBreak);
Clipboard.Clear();
}
}
}
doc2.SaveAs2("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
doc.Close(WdSaveOptions.wdDoNotSaveChanges);
doc2.Close(WdSaveOptions.wdDoNotSaveChanges);
app.Documents.Open("OTSU" + myDate[0].Month + "_" + myDate[0].Year + ".docx");
}
}
}
I have looked at this plunker.
http://plnkr.co/edit/WJzTr8AR8dhWIjXELNY1?p=preview
It filters on first characters. Has anyone attempted to perform this filtering based on a substring search. If so please let me know
I worked on modifying the filter text as shown
angular.forEach(filterBarPlugin.scope.columns, function(col) {
if (col.visible && col.filterText) {
var filterText = (col.filterText.indexOf('*') == 0 ? col.filterText.replace('*', '') : col.filterText + "^") + ";";
searchQuery += col.displayName + ": " + filterText;
}
});
The original plunkr is design filtering from the beginning characters. If you went to filtering from the substring, you can try * begin filter textbox.
If you don't like it, you can modify filterBarPlugin function :
var filterText = (col.filterText.indexOf('*') == 0 ? col.filterText.replace('*', '') : "^" + col.filterText) + ";";
searchQuery += col.displayName + ": " + filterText;
To
var filterText = col.filterText +'; ';
searchQuery += col.displayName + ": " + filterText;
Example
updated: fixed not allow for multiple column sorting, thanks #mainguy
This is not really an answer but more an update to #allyusd's answer.
He is basically right, but his wildcardless solution does not allow for multi column sorting because a semicolon is missing.
With these small changes:
angular.forEach(filterBarPlugin.scope.columns, function(col) {
if (col.visible && col.filterText) {
var filterText = col.filterText +'; ';
searchQuery += col.displayName + ": " + filterText;
}
});
you can filter in this plunk for name=or AND age=4 and you will get Enors as result.
As I said: Just an update, kudos to allyusd!
I read on many forums about how to implement a solution for view pagionation, but I didn't solve it.
I created $$ViewTemplateDefault containing some personalized hotspotbuttons for Next, Previous and a text field $$ViewBody. ( or, alternatively, an embedded view ).
Any tips and help will be really appreciated.
I will explain in a couple words, just to be clear:
So, initially: the first 30 lines will appear => in a right corner: Page 1.
If Next is clicked => the next 30 lines => Page 2. and so on.
Here is a working solution for categorized views too. It calculates the current page number based on the previous page number and uses cookies.
Add to your form a Path-Thru HTML text <span id="pageNumber"></span > for the page number:
and add following code to form's onLoad event as Web/JavaScript:
function getURLParameter(parameter) {
return decodeURIComponent((new RegExp('[?|&]' + parameter + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for(var i=0; i<ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name)==0) return c.substring(name.length,c.length);
}
return "";
}
function compareStart(start1, start2) {
var list1 = start1.split(".");
var list2 = start2.split(".");
for (i=0; i <100; i++) {
var value1 = list1[i];
var value2 = list2[i];
if (value1 == null) {
return value2 == null ? 0 : -1;
} else if (value2 == null) {
return 1;
}
value1 = Math.round(value1);
value2 = Math.round(value2);
if (value1 !== value2) {
return value1 < value2 ? -1 : 1;
}
}
}
var start = getURLParameter("Start");
var page = "1";
if (start == null || start === "1") {
window.name = Math.floor((Math.random()*10000)+1);
start = "1";
} else {
page = getCookie("page" + window.name);
var oldStart = getCookie("start" + window.name);
page = Math.round(page) + compareStart(start, oldStart);
}
document.getElementById('pageNumber').innerHTML = page;
document.cookie = "page" + window.name + "=" + page;
document.cookie = "start" + window.name + "=" + start;
How does it work?
The commands #DbCommand("Domino"; "ViewNextPage") and #DbCommand("Domino"; "ViewPreviousPage") return an URL with parameter "&Start=". This is the row number in view where the current page starts. For categorized views they return a hierarchical number like "&Start=1.2.4.2". That means that the view starts at the first main topic, subtopic 2, subsubtopic 4, document 2.
This parameter "&Start=" gives us the possibility to recognize if user pressed "prev" or "next": we just compare the URL "&Start=" parameter of current and former page.
For that, we have to remember the URL "&Start=" parameter and put it into a cookie "start".
We also need to save the current page number. We put it into a cookie "page".
At onload event we calculate the current page number based on previous page number:
if "&Start=" parameter is larger now then we add 1
if "&Start=" parameter is smaller now then we subtract 1
if "&Start=" parameter didn't change then we keep the former value
If "&Start=" parameter is empty we know we are on page 1.
Here is one other thing we have to deal with: cookies are saved per user session not per browser tab. That means, if we have two views open in browser same cookies "start" and "page" would be used. To avoid that, we have to add to cookie name something tab specific. I use for that a random four digit number and save it in window.name which is tab specific.
I understand your question that you have a working form $$ViewTemplateDefault and now looking for a possibility to show the current page number "Page nn" in that form.
I assume that you use #DbCommand("Domino"; "ViewNextPage") for getting next page and #DbCommand("Domino"; "ViewPreviousPage") for getting previous page.
Those next and prev functions working the way that always one document will "overlap". If you have 30 lines per page and click next, then last document will be first in next page and next 29 show up in addition. You can watch that in used URL parameter "&Start=": 1 ... 30 ... 59 ... 88 ...
Knowing this you can count the current page number this way:
_start := #ToNumber(#Replace(#UrlQueryString("start"); ""; "1"));
_count := #ToNumber(#Replace(#UrlQueryString("count"); ""; "30")) - 1;
#Integer((#ToNumber(_start) / _count) + 1)
Be aware that this will work for non-categorized and non-collapsible views only.
A more sophisticated solution you can find here. It has additional features like GoTo page and Documents per page.
If you have the chance for your project then use XPages instead. You can do pagination much easier as it is available "out of the box".
Update:
You won't find a reasonable solution for categorized views. If you don't want to use Domino Data/Access Services REST API you have to live with the Domino view URL parameters (look here for "OpenView"). You aren't able to tell from "&Start=" or any other parameter on which page you are currently on.
The easiest way to get a good working pagination is using XPages. Hope you are allowed to use it in your project...
I have a configurable product with 3 options, see below:
I want to replace the +£24.00 and the +£75.00 with the actual prices of the products.
So instead it would say: £69.00 and £120.00
I have located the code being in js/varien/product.js
I've spent a bit of time chopping and changing the code, but can't quite decipher what needs to change. Line 240 downwards in this file handles the JavaScript events for configurable products.
This is performed by javascript. You need to modify the method getOptionLabel in js/varien/configurable.js (this is Magento 1.5.1.0, your milage may vary depending on the version you're using).
This method receives the option and the price difference to be applied. If you want to just show the absolute price of the different options, you need to calculate them yourself, using the absolute base value of the configurable product and the absolute difference of the option.
The first few lines of the method look like this:
getOptionLabel: function(option, price){
var price = parseFloat(price);
Change that so you get the absolute base price and the absolute difference of the option. Then add them together to get the final absolute price of the option. Like this:
getOptionLabel: function(option, price){
var basePrice = parseFloat(this.config.basePrice);
// 'price' as passed is the RELATIVE DIFFERENCE. We won't use it.
// The ABSOLUTE DIFFERENCE is in option.price (and option.oldPrice)
var absoluteDifference = parseFloat(option.price);
var absoluteFinalPrice = basePrice + absoluteDifference;
// var price = parseFloat(price);
var price = absoluteFinalPrice;
Then you need to get rid of the + and - symbols in the options. Later on in the same method, when you call this.formatPrice, just change the second paramter to false in each call.
if(price){
if (this.taxConfig.showBothPrices) {
str+= ' ' + this.formatPrice(excl, false) + ' (' + this.formatPrice(price, false) + ' ' + this.taxConfig.inclTaxTitle + ')';
} else {
str+= ' ' + this.formatPrice(price, false);
}
Some more notes about this:
You will find another identical object called Product.Config being created in js/varien/product.js. As far as I can tell, this does absolutely nothing as it is replaced by js/varien/configurable.js.
Also, if just change js/varien/configurable.js, the next time you upgrade Magento you will probably lose your changes. Better to create another file like js/varien/my_configurable.js or whatever, and call it in the config file (product.xml) for whatever theme you are using.
This extension might be helpful, I've used it in the past (and it appears to be maintained):
http://www.magentocommerce.com/magento-connect/Matt+Dean/extension/596/simple-configurable-products
In magento 1.9 the .js method doesn't seem to work anymore.
Instead I updated Abstract.php (/app/code/core/Mage/Catalog/Block/Product/View/Options/Abstract.php), copy this file to /app/code/local/Mage/Catalog/Block/Product/View/Options/Abstract.php. On line 128, change the $_priceInclTax and $_priceExclTax variables to the following:
$_priceInclTax = $this->getPrice($sign.$value['pricing_value'], true)+$this->getProduct()->getFinalPrice();
$_priceExclTax = $this->getPrice($sign.$value['pricing_value'])+$this->getProduct()->getFinalPrice();
I've seen similar solutions, but this is the only way to ensure it also works with things such as negative product options and special price discounts.
Found a solution here that works on Magento 1.9 but it overrides core code, it should be done so that it does not override core.
I've tried something like this in a new js file, but somehow the core configurable.js get's messed up, maybe someone can come up with a way so that id doesn't.
Product.Config.prototype.getOptionLabel = Product.Config.prototype.getOptionLabel.wrap(function(parentMethod){
// BEGIN:: custom price display update
var basePrice = parseFloat(this.config.basePrice);
// 'price' as passed is the RELATIVE DIFFERENCE. We won't use it.
// The ABSOLUTE DIFFERENCE is in option.price (and option.oldPrice)
var absoluteDifference = parseFloat(option.price);
// var price = parseFloat(price);
if(absoluteDifference){
// console.log(option);
price = basePrice + absoluteDifference;
} else {
price = absoluteDifference;
}
// END:: custom price display update
if (this.taxConfig.includeTax) {
var tax = price / (100 + this.taxConfig.defaultTax) * this.taxConfig.defaultTax;
var excl = price - tax;
var incl = excl*(1+(this.taxConfig.currentTax/100));
} else {
var tax = price * (this.taxConfig.currentTax / 100);
var excl = price;
var incl = excl + tax;
}
if (this.taxConfig.showIncludeTax || this.taxConfig.showBothPrices) {
price = incl;
} else {
price = excl;
}
var str = option.label;
if(price){
if (this.taxConfig.showBothPrices) {
// BEGIN:: custom price display update
// NOTE:: 'true' was changed to 'false' in 3 places.
str+= ' ' + this.formatPrice(excl, false) + ' (' + this.formatPrice(price, false) + ' ' + this.taxConfig.inclTaxTitle + ')';
} else {
str+= ' ' + this.formatPrice(price, false);
// END:: custom price display update
}
}
return str;
});
Edit the file js/varien/product.js, looking at line number 691
If we were to change the attribute prices from the product detail page, the trigger will fire here. Just check with alert(price);, and you can get the changeable price.
In 1.7 (not sure when this was changed) things were changed around. it ends up that the price string is built in PHP, inside Mage/Catalog/Block/Product/View/Options/Abstract.php in the _formatPrice function when called from Mage/Catalog/Block/Product/View/Options/Type/Select.php
Notice that changing any of those 2 classes is going to provoke a change through the site and not just in that specific combo
I am suprised at how Magento can use by default such a weird logic.
The ability to see different prices per variant should be available, and perhaps even the default one.
Prestashop does this, and even automatically switches images when selecting each variant!
in Magento 1.9
open js/varien/configurable.js
goto function getOptionLabel
modify this function code as required.
var assets1 = data.SelectNodes("//asset[#id]=" + oldBinaryAssetId);
var assets2 = data.SelectNodes("//Asset[#id]=" + oldBinaryAssetId);
Is it possible to make 1 xpath query of the two above?
Your XPath is wrong to be gin with. You probably mean:
data.SelectNodes("//Asset[#id = '" + oldBinaryAssetId + "']");
To combine both variants (upper- and lower-case), you could use:
data.SelectNodes("//*[(name() = 'Asset' or name() = 'asset') and #id = '" + oldBinaryAssetId + "']");
or
data.SelectNodes("(//Asset | //asset)[#id = '" + oldBinaryAssetId + "']");
If you have any way to avoid the // operator, I recommend doing so. Your queries will be faster when you do, though this might only be noticable with large input documents.