YUI 2.9 TreeView - treeview

I am able to render a tree using YAHOO.widget.TreeView yui 2.9.
Using pre made tags
<ul> <li> Products </li> </ul>
I am able to get the label i.e Products using node.label
YAHOO.util.Event.on('allProductSaveButton','click',function() {
var hiLit = rightProductTree.getNodesByProperty('highlightState',1);
if (YAHOO.lang.isNull(hiLit)) {
YAHOO.log("None selected");
} else {
var labels = [];
for (var i = 0; i < hiLit.length; i++) {
var node = hiLit[i];
if(node.children.length<=0) {
labels.push(hiLit[i].label); }
}
alert("Highlighted nodes:\n" + labels.join("\n"), "info", "example");
}
});
I want to insert id of the Products in the html and get the id of label as well. so where should I place id attribute inside or where?

I am not sure you can set your own id on the markup. TreeView is one of the oldest widgets in YUI 2 and it uses a particularly funny markup because the supported CSS styles in those days were quite pathetic, thus, what part of that funny markup are you going to apply that id to?
If what you want is to give a tree-node an identifier that you can later use to retrieve it, then use custom properties. Then, calling getNodesByProperty will allow you to retrieve the node by the value of that extra property.

I got a solution. I inserted the label element inside the span element that was inside the li element i.e
<ul>
<li> <span> <label id="444" > Product </label> </span>
</li>
</ul>
then using YAHOO.util.Dom I traversed and got the id attribute of label element.
YAHOO.util.Event.on('GroupsProductSaveButton', 'click', function() {
var hiLit = rightProductTree2.getNodesByProperty('highlightState', 1);
if (YAHOO.lang.isNull(hiLit)) {
alert("None selected");
} else {
var labels = [];
for (var i = 0; i < hiLit.length; i++) {
var node = hiLit[i];
if(node.children.length<=0) {
labels.push(YAHOO.util.Dom.get(hiLit[i].contentElId).getElementsByTagName('label')[0].getAttribute("value")); }
}
alert("Highlighted nodes:\n" + labels.join("\n"), "info", "example");
ProductGroupDWR.displaySelectedNodes(labels, function(data) {
});
}
});

Related

How do I update model in Master detail razor page with AJAX results

I have a parent table with rows.
When they select a row, an AJAX call fires that returns the child details.
I have multiple text boxes showing child properties
<div class="row">
#Html.CheckBoxFor(m => m.Child.Property)
#Html.LabelFor(m => m.Child.Property)
</div>
but I can't see how to update the text boxes with the child I get back in AJAX results.
The best I've been able to do is manually updating each field from the 'complete' method. But I've got about 30 more fields to add and it feels like the wrong approach.
How do I bind the edit boxes to the returned model without using partials and without refreshing the entire page?
I added Child as a property in the #model, and the TextFor appears to bind properly. But of course
#Model.Child = child
does not. So they never show any data.
This question was based on a misunderstanding on my part. At first I deleted the question when I realized my mistake. I'm reinstating it because I think it is an easy mistake for a noobie to fall into and once you do, the answer is hard to sort out.
The problem is that #model no longer exists once the page is rendered. There is no data binding going on behind the scenes as I thought there was.
Your options are
populating the elements manually. (this will need editing to fit your particular elements)
function DisplayMergeSection(data) {
for (var key of Object.keys(data)) {
DisplayElement(data, key, "#Clients_");
}
}
function DisplayElement(data, key, prefix) {
return;
var val = data[key];
var valString = data[key + "String"];
var element = $(prefix + key)[0];
if (element && element.type === 'text') {
if ((val || '').toString().indexOf("Date(") > -1) {
var dtStart = new Date(parseInt(val.substr(6)));
element.value = moment(dtStart).format('MM/DD/YYYY');
} else {
element.value = val;
}
} else if (element && element.type === 'checkbox') {
element.checked = val;
} else if (element && element.type === 'select-one') {
element.value = valString;
} else if (element && element.nodeName === 'DIV') {
if ((val || '').toString().indexOf("Date(") > -1) {
var dtStart = new Date(parseInt(val.substr(6)));
element.innerText = moment(dtStart).format('MM/DD/YYYY');
} else {
element.innerText = val;
}
}
}
create a bunch of observables with knockout and then set up data binding. This is a lot cleaner.
https://knockoutjs.com/documentation/json-data.html
set up a mapping with the knockout plugin.
https://knockoutjs.com/documentation/plugins-mapping.html

Unable to find element with xpath due to different division

Could you help to fix this error. Received error as:
Unable to find element with xpath
Below the tags for the element which is a Text area
<td nowrap="">
<script>
function clipBrdAction(evt, fieldName) {
evt = evt||window.event;
if(evt.ctrlKey && evt.keyCode==67) {
document.execCommand('copy');
//var temp = $(fieldName).value;
//clipboardData.setData('Text', temp);
//$(fieldName).value = clipboardData.getData('Text');
}
else if(evt.ctrlKey && evt.keyCode==86) {
document.execCommand('paste');
//$(fieldName).value = clipboardData.getData('Text');
}
else if(evt.ctrlKey && evt.keyCode==88) {
document.execCommand('cut');
//var temp = $(fieldName).value;
//clipboardData.setData('Text', temp);
//$(fieldName).value = '';
} else if(evt.keyCode==46) {
document.execCommand('delete');
//var selStart = $(fieldName).selectionStart;
//var selEnd = $(fieldName).selectionEnd;
//var fieldLen = $(fieldName).value.length;
//if (selEnd == fieldLen)
// temp = $(fieldName).value.substr(0,selStart);
//else if (selEnd > selStart)
// temp = $(fieldName).value.substr(0,selStart)+ $(fieldName).value.substr(selEnd, fieldLen);
//else
// temp = $(fieldName).value.substr(0,selStart)+ $(fieldName).value.substr((+selEnd + +1), fieldLen);
//clipboardData.setData('Text', temp);
//$(fieldName).value = clipboardData.getData('Text');
}
</script>
<textarea id="nrpsFilter" rows="3" onkeypress="return checkIt(event,'');" cols="30" title="" onblur="this.value=trim(this.value);" onkeyup="" onkeydown="return clipBrdAction(event, 'nrpsFilter');" name="nrpsFilter"/>
</td>
And my code is:
driver.findElement(By.xpath("//*[#id='nrpsFilter']")).sendKeys("*1??0*");
In Firepath, the element is identifiable, after when i search for another element that is under same division (div tag) but not identifiable after searching for an element from different division. Does that mean I should Switch to the division in my code? Both the divisions are under same Frame.
Ok then just before using Sendkeys please switch to the iframe first after that your code will work without any problem.
driver.switchTo().frame("frame name");
// perform your action
// after you have performed all your action inside the iframe
// plz switch back to the default content
driver.switchTo().defaultContent();
// now perform your user action outside that iframe
Hope this helps you
Try this and see if it works. I took it from your comment but rearranged a couple statements. I think you want the final sendkeys() to be in the IFRAME also, right? We really need more complete HTML to help any further.
driver.findElement(By.xpath("//*[#id='first']//span")).click(); // (1. Click Dropdown)
driver.findElement(By.xpath("//*[#id='ui-id-33']/span")).click(); // (2. Click SubDropDown )
driver.findElement(By.xpath("//a[contains(text(),'Quick Search')][#id='referential_quicksearch']")).click(); // (3.Click the link)
driver.findElement(By.xpath("//*[#id='nrpsFilter']")).sendKeys("1?0*");// (Enter in textArea)
driver.switchTo().defaultContent();

use Dojo to add an onclick event for a series of img

A button is clicked to trigger LoadImages method to load a series of pictures into the web page. I want to add an onclick event for each picture so when user click it, the picture name is displayed. How to use Dojo to achieve this?
LoadImages(PictureNames){
var resultUl = new Builder('<ul />');
for (i = 0; i < PictureNames.length; i++){
resultUl.append('<li><img id=' + PictureNames[i] + ' src="./images/' + PictureNames[i] + '.jpg" height="200" width="250" class="photo"/></li>');
}
dom.byId('Pictures').innerHTML = resultUl;
}
DisplayPictureName(picturename)
{
dom.byId('PictureName').value = picturename;
}
<label id="PictureName">here displays picture name</label>
<div id="Pictures"></div>
Make the elements using dojo/dom-construct and attach events using dojo/on.
var resultUl = domConstruct.create('ul');
for (i = 0; i < PictureNames.length; i++){
var image= domConstruct.create('img', {
id: PictureNames[i]',
src: "./images/"+ PictureNames[i],
style: {"height: 200px; width: 250px"},
class: "photo"});
var li= domConstruct.create('li');
domConstruct.place(li, resultUl);
domConstruct.place(image, li);
dojo.on(image, 'click', this.DisplayPictureName());
}
dom.byId('Pictures').innerHTML = resultUl;

Angularjs - optimizing the watcher of ngrepeat to watch only certain properties of collection

In my angularJS application I have a collection (array) of rather large objects. I need to bind to this collection in various places (e.g. to display the property: name of the contained objects) - binding is essential, as these names might change.
As the normal ngRepeat would observe the whole collection by strict equality comparison I am concerned about application speed (we are talking about objects with thousends of properties or more) - I actually just need to observe general changes in the collection (like length, changes of the single references in case two elements are flipped and some specific properties like the mentioned .name property)
I am thinking about using the following approach (basically creating a custom copy of the collection and manually bind to the original collection.
My question:
Is the described approach better than watching the original collection (by equality - as it is my understanding the ngRepeater does) or is there some better approach (e.g. defining some kind of compare callback in a watch statement to check only for changes in certain properties,...)
<script>
function QuickTestController($scope) {
// simulate data from a service
var serviceCollection = [], counter = 0,
generateElement = function() {
var element = { name:'name' + ++counter };
//var element = { name:'name' };
for (var j = 0 ; j < 5 ; j++) element['property' + j] = j;
return element;
};
for (var i = 0 ; i < 5 ; i++) {
serviceCollection.push( generateElement() );
}
// in the view controller we could either bind to the service collection directly (which should internally use a watchCollection and watch every single element for equality)
$scope.viewCollection = serviceCollection;
// watching equality of collection
/*
$scope.$watch('_viewCollectionObserve', function(newValue, oldValue) {
console.log('watch: ', newValue, oldValue);
}, true);
*/
// or we could create our own watchCollection / watch structure and watch only those properties we are interested in
$scope._viewCollectionObserve = serviceCollection;
var viewCollectionManual = [],
rebuildViewCollection = function() {
viewCollectionManual = [];
for (var i = 0, length = serviceCollection.length ; i < length ; i++) {
viewCollectionManual.push( {name:serviceCollection[i].name } );
}
console.log('- rebuildViewCollection - ');
$scope.viewCollection2 = viewCollectionManual;
},
watchCollectionProperties = [],
unregisterWatchCollection = function() {},
rebuildWatchCollectionProperties = function() {
watchCollectionProperties = [];
for (var i = 0, length = serviceCollection.length ; i < length ; i++) {
watchCollectionProperties.push('_viewCollectionObserve[' + i + ']'); // watch for ref changes
watchCollectionProperties.push('_viewCollectionObserve[' + i + '].name'); // watch for changes in specific properties
}
unregisterWatchCollection();
var watchString = '[' + watchCollectionProperties.join(',') + ']';
unregisterWatchCollection = $scope.$watchCollection(watchString, function(newValues, oldValues) {
console.log('watchCollection: ', newValues, oldValues);
rebuildViewCollection();
});
};
$scope.$watch('_viewCollectionObserve.length', function(newValue, oldValue) { // watch add / remove elements to / from collection
console.log('watch / length: ', newValue, oldValue);
rebuildWatchCollectionProperties();
});
// rebuildViewCollection();
rebuildWatchCollectionProperties();
// click handler ---
$scope.changName = function() { serviceCollection[0].name += '1'; };
$scope.changeSomeProperty = function() { serviceCollection[0].property0 += 1; };
$scope.removeElement = function() { serviceCollection.splice(0, 1); };
$scope.addElement = function() { serviceCollection.push( generateElement() ); };
$scope.switchElement = function() {
var temp = serviceCollection[0];
serviceCollection[0] = serviceCollection[1];
serviceCollection[1] = temp;
};
// will of course not react to this (this is desired behaviour!)
$scope.removeCollection = function() { serviceCollection = []; };
}
</script>
<div data-ng-controller="QuickTestController">
<ul>
<li data-ng-repeat="element in viewCollection">{{element.name}} {{element}}</li>
</ul>
<hr>
<ul>
<li data-ng-repeat="element in viewCollection2">{{element.name}} {{element}}</li>
</ul>
<button data-ng-click="changName()">changName</button>
<button data-ng-click="changeSomeProperty()">changeSomeProperty</button>
<button data-ng-click="removeElement()">removeElement</button>
<button data-ng-click="addElement()">addElement</button>
<button data-ng-click="switchElement()">switchElement</button>
<hr>
<button data-ng-click="removeCollection()">removeCollection (see comment)</button>
</div>
Any help / opinions would be greatly appreciated - please note that I tried to create a fiddle to demonstrate my approach but failed :-(
(I know that benchmarking might be a possible solution to test my approach, but I´d rather know the opinion of the angularjs pros in here)
thanks,
matthias
I think what you're looking for is bindonce, which is a high performance binding directive that lets you bind a property or expression once in AngularJS, just as what its name suggests.
One thing you can also try is a 'track by' expression. If you have a property that is unique for each object in the collection, you can pass that to your repeat expression.
<div ng-repeat="item in items track by item.id"></div>
I think Angular will then just watch that property on each of your items. So this should improve performance, but I don't know how much.

How to make the tab get focus

In my gridComplete function, depending on certain values in the datarow, I want to move the focus to a different tab. The gridCompelete function will be something like
var grid = $('#grdResults');
var m = grid.getDataIDs();
for (var i = 0; i < m.length; i++) {
var rowData = grid.getRowData(m[i]);
if (rowData.errorMessage != '') {
alert(rowData.errorMessage);
$('#UploadMain').focus();
}
}
Obviously the .focus() does not seem to work. Given below is the part of the view that has the code for the tabs
<div id="editTabs">
<ul>
<li>Main</li>
<li>Data Validation</li>
</ul>
<div id="UploadMain">
<fieldset>
.......
What do I need to have the focus moved?
Are you looking for the select() method?
$("#editTabs").tabs("select", 0); // Activate first tab.
Or:
$("#editTabs").tabs("select", "#UploadMain"); // Activate "UploadMain" tab.

Resources