I'm trying to build a grid server side, I wrote this in a cshtml file:
#{
var items = (List<FancyItem>)ViewBag.items;
var col = 0;
var colMax = 3;
foreach (var it in items) {
if (col == 0) {<tr>}
if (col == 0) {</tr>}
col++;
if (col == colMax) {col = 0;}
}
}
So in theory, the column creation code would go in between the two if's, however, I never got that far. The two if's are supposed to create rows when the columns reset but it seems everything after < tr> gets interpreted as plain text. I don't know what to do, what kind of syntax candy would fix this?
I see your issue - Razor expects you to close any opening tags or it thinks you are still writing HTML
Try this:
Edit: Added #s to get the content to write to the HTML output stream
foreach (var it in items)
{
if (col == 0)
{
#Html.Raw("<tr>");
}
if (col == 0) {
#Html.Raw("</tr>");
}
col++;
if (col == colMax)
{
col = 0;
}
}
Related
I'm currently using this formula to highlight duplicates in my spreadsheet.
=ARRAYFORMULA(COUNTIF(A$2:$A2,$A2)>1)
Quite simple, it allows me to skip the first occurrence and only highlight 2nd, 3rd, ... occurrences.
I would like the formula to go a bit further and highlight near duplicates as well.
Meaning if there is only one character difference between 2 cells, then it should be considered as a duplicate.
For instance: "Marketing", "Marketng", "Marketingg" and "Market ing" would all be considered the same.
I've made a sample sheet in case my requirement is not straightforward to understand.
Thanks in advance.
Answer
Unfortunately, it is not possible to do this only through Formulas. Apps Scripts are need as well. The process for achieving your desired results is described below.
In Google Sheets, go to Extensions > Apps Script, paste the following code1 and save.
function TypoFinder(range, word) { // created by https://stackoverflow.com/users/19361936
if (!Array.isArray(range) || word == "") {
return false;
}
distances = range.map(row => row.map(cell => Levenshtein(cell, word))) // Iterate over range and check Levenshtein distance.
var accumulator = 0;
for (var i = 0; i < distances.length; i++) {
if (distances[i] < 2) {
accumulator++
} // Keep track of how many times there's a Levenshtein distance of 0 or 1.
}
return accumulator > 1;
}
function Levenshtein(a, b) { // created by https://stackoverflow.com/users/4269081
if (a.length == 0) return b.length;
if (b.length == 0) return a.length;
// swap to save some memory O(min(a,b)) instead of O(a)
if (a.length > b.length) {
var tmp = a;
a = b;
b = tmp;
}
var row = [];
// init the row
for (var i = 0; i <= a.length; i++) {
row[i] = i;
}
// fill in the rest
for (var i = 0; i < b.length; i++) {
var prev = i;
for (var j = 0; j < a.length; j++) {
var val;
if (b.charAt(i) == a.charAt(j)) {
val = row[j]; // match
} else {
val = Math.min(row[j] + 1, // substitution
prev + 1, // insertion
row[j + 1] + 1); // deletion
}
row[j] = prev;
prev = val;
}
row[a.length] = prev;
}
return row[a.length];
}
In cell B1, enter =TypoFinder($A$2:$A2,$A2). Autofill that formula down the column by draggin.
Create a conditional formatting rule for column A. Using Format Rules > Custom Formula, enter =B2:B.
At this point, you might wish to hide column B. To do so, right click on the column and press Hide Column.
The above explanation assumes the column you wish to highlight is Column A and the helper column is column B. Adjust appropriately.
Note that I have assumed you do not wish to highlight repeated blank columns as duplicate. If I am incorrect, remove || word == "" from line 2 of the provided snippet.
Explanation
The concept you have described is called Levenshtein Distance, which is a measure of how close together two strings are. There is no built-in way for Google Sheets to process this, so the Levenshtein() portion of the snippet above implements a custom function to do so instead. Then the TypoFinder() function is built on top of it, providing a method for evaluating a range of data against a specified "correct" word (looking for typos anywhere in the range).
Next, a helper column is used because Sheets has difficulties parsing custom formulas as part of a conditional formatting rule. Finally, the rule itself is implemented to check the helper column's determination of whether the row should be highlighted or not. Altogether, this highlights near-duplicate results in a specified column.
1 Adapted from duality's answer to a related question.
Is there a way to tell the count of characters of all text fields in some of our content items? We need to estimate a translation price for our content items.
You can use Delivery API to retrieve your items and run a quick javascript to count the characters for you. First, get all your items (or a subset, depending on what you need) with the call excluding all the modular content (linked items) like this:
https://deliver.kenticocloud.com/<projectid>/items?depth=0
Then you can use browser console to run this piece of code:
var response = JSON.parse(document.getElementsByTagName("BODY")[0].textContent);
var noOfChars = 0;
for (var x = 0; x < response.items.length; x++) {
var p = response.items[x].elements;
for (var key in p) {
if (p[key].type=='rich_text' || p[key].type=='text') {
noOfChars += strip(p[key].value).length;
}
}
}
noOfChars;
function strip(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp.textContent || tmp.innerText || "";
}
And hit enter. This is what the result will look like:
I have 30 columns and 1000 rows, I would like to compare column1 with another column. IF the value dont match then I would like to colour it red. Below is a small dataset in my spreadsheet:
A B C D E F ...
1 name sName email
2
3
.
n
Because I have a large dataset and I want to storing my columns in a array, the first row is heading. This is what I have done, however when testing I get empty result, can someone correct me what I am doing wrong?
var index = [];
var sheet = SpreadsheetApp.getActiveSheet();
function col(){
var data = sheet.getDataRange().getValues();
for (var i = 1; i <= data.length; i++) {
te = index[i] = data[1];
Logger.log(columnIndex[i])
if (data[3] != data[7]){
// column_id.setFontColor('red'); <--- I can set the background like this
}
}
}
From the code you can see I am scanning whole spreadsheet data[1] get the heading and in if loop (data[3] != data[7]) compare two columns. I do have to work on my colour variable but that can be done once I get the data that I need.
Try to check this tutorial if it can help you with your problem. This tutorial use a Google AppsScript to compare the two columns. If differences are found, the script should point these out. If no differences are found at all, the script should put out the text "[id]". Just customize this code for your own function.
Here is the code used to achieve this kind of comparison
function stringComparison(s1, s2) {
// lets test both variables are the same object type if not throw an error
if (Object.prototype.toString.call(s1) !== Object.prototype.toString.call(s2)){
throw("Both values need to be an array of cells or individual cells")
}
// if we are looking at two arrays of cells make sure the sizes match and only one column wide
if( Object.prototype.toString.call(s1) === '[object Array]' ) {
if (s1.length != s2.length || s1[0].length > 1 || s2[0].length > 1){
throw("Arrays of cells need to be same size and 1 column wide");
}
// since we are working with an array intialise the return
var out = [];
for (r in s1){ // loop over the rows and find differences using diff sub function
out.push([diff(s1[r][0], s2[r][0])]);
}
return out; // return response
} else { // we are working with two cells so return diff
return diff(s1, s2)
}
}
function diff (s1, s2){
var out = "[ ";
var notid = false;
// loop to match each character
for (var n = 0; n < s1.length; n++){
if (s1.charAt(n) == s2.charAt(n)){
out += "–";
} else {
out += s2.charAt(n);
notid = true;
}
out += " ";
}
out += " ]"
return (notid) ? out : "[ id. ]"; // if notid(entical) return output or [id.]
}
For more information, just check the tutorial link above and this SO question on how to compare two Spreadsheets.
I use this code to replace text of bookmark in word :
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open("doc3.docx", true))
{
var bookmarkStarts = wordDoc.MainDocumentPart.Document.Body.Descendants<BookmarkStart>();
foreach (var start in bookmarkStarts)
{
OpenXmlElement elem = item.NextSibling();
while (elem != null && !(elem is BookmarkEnd))
{
OpenXmlElement nextElem = elem.NextSibling();
elem.Remove();
elem = nextElem;
}
item.Parent.InsertBefore<Run>(new Run(new Text("Hello")), item);
}
wordDoc.Close();
}
But this not work where the bookmark is in the table.
Have you checked that you don't delete any bookmarks with your approach?
I've run your test code after editing a little (you don't have a var name items in your example code), and I've succesfully inserted Hello in 2 bookmarks out of a table, and 2 in a table, without any issues.
Which leads me to believe your problem lies elsewhere.
Have you looked at the open-xml in your document after you've run your program?
Is there any errors?
I've experienced bookmarks being placed the oddest places in a word-document when you leave the placing to word, and not you.
You can also end up with bookmarks overlapping each other like this
<bookmark1 start><xml xml><bookmark2 start><bookmark1 end><xml xml><bookmark2 end>
If you run into that case, your code will delete the bookmarkstart 2 before it reaches bookmarkend 1, and that will cause your bookmark to not be replaced.
You'll easily run into that problem with larger complex documents.
The way I solved it was to "sort" the bookmarks before doing any editing.
So the example above would become
<bookmark1 start><xml xml><bookmark1 end><bookmark2 start><xml xml><bookmark2 end>
after the sort
The code I use to do this look like this:
var bookmarks = mainPart.Document.Body.Descendants<BookmarkStart>();
for (int i = 0; i < bookmarks.Count(); i++)
{
var bks = bookmarks.ElementAt(i);
var next = bks.NextSibling();
if (next is BookmarkEnd)
{
var bme = (BookmarkEnd)next;
if (int.Parse(bks.Id) - int.Parse(bme.Id) == 1)
{
var copy = (BookmarkEnd)next.Clone();
bks.Parent.RemoveChild<BookmarkEnd>(bme);
bks.Parent.InsertBefore<BookmarkEnd>(copy, bks);
}
}
}
Which i'll admit isn't totally fool-proof but have worked well for me.
Another check you can add, to avoid deleting bookmarks is in your replace method
This will make sure you don't delete bookmarkstarts as you remove elements when inserting text
while (elem != null && !(elem is BookmarkEnd)) //fjern elementer
{
OpenXmlElement nextElem = elem.NextSibling();
if (elem.LocalName != "bookmarkStart")
elem.Remove();
elem = nextElem;
}
Good luck :)
I have one script behind one spreedsheet and I'm trying to export some cell values to document, and than email the pdv version of temp document..(trash it latter). I have problem with value I get or in the way I'm getting the value from spreedsheet to doc.. I can't manipulate the decimal point..
// fix the price currency display and alignment in GOOGLE DOCUMENT TABLE!
for (var i = 0; i < price.getNumRows(); i++){
for (var j = 0; j < price.getRow(i).getNumCells(); j++){
var temp = price.getCell(i, j);
temp.getChild(0).asParagraph().setSpacingAfter(0);
if((j == 6 || j == 7) && !temp.getText() == "" ) {
(i > 0) ? temp.replaceText(temp.getText(), temp.getText() + " kn") : void false; // skip the first line with header titles...
temp.getChild(0).asParagraph().setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
}
}
}
after (i > 0) there is temp.getText() value.. that sometimes is like: 55,987654 and I would like that to round to two digits.. but can't :(
Thanks for help!
I have found solution..
it's very simple but did take me some time.. hope that can help someone else with similar situation
parseFloat(temp.getText()).toFixed(2) + " kn")
this did the trick and the output is something like: 55,99 kn!