How to display parent menu item in node template? Drupal 7 - drupal-7

How do i display the parent menu item in the node template?
I want to display parent menu item along with current page; but i dont need others.
Edit: I enabled menu breadcrumb module and added the following code:
<?php
$menuParent = menu_get_active_trail();
if (sizeof ($menuParent) >= 2 && $menuParent[2]) {
$menuParent = $menuParent[1]['link_title'];
print $menuParent;
}
?>
It is working fine, but I am getting an error for the pages which doesn't have 2nd level navigation:
Error: Notice: Undefined offset: 2 in include()
I thought my condition sizeof will take care of the problem, but not working.

Use PHP array tools to get you the right item in the array:
<?php
$menuParent = menu_get_active_trail();
//get rid of the last item in the array as it is the current page
$menuParentPop = array_pop($menuParent);
//Just grab the last item in the array now
$menuParent = end($menuParent);
//if it is not the home page and it is not an empty array
if(!empty($menuParent) && $menuParent['link_path'] != ''){
print $menuParent['title'];
} else{
print $title;
}
?>

You're checking $menuParent[2] but then using $menuParent[1]. Maybe check $menuParent[1]:
if (sizeof ($menuParent) >= 2 && $menuParent[1]) {
PHP's arrays are zero-indexed, so slot 1 is the second slot.

Related

getting values of all ticked items in checkboxes

Let us suppose that I have three checkboxes and each checkbox has certain items to be checked say Item 1 ,Item 2,Item 3 which has value 'a' ,'b','c'.So if we click on item1,item2 and mark them ,we get an array with values a and b .Now if we click item3,we would get c .Again if we go to another checkbox now and click on another item in another checkbox,we would get another array which holds the values for the items we marked in second checkbox .
I need to store all marked items in an array and display it .The problem is to get all the ticked items for all the different checkboxes.
will the following perhaps set you in the right direction?
var checkboxValues = [];
var checkboxes = document.querySelectorAll('input[type="checkbox"]');
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
checkboxValues.push(checkboxes[i].value);
}
}
console.log('checkboxValues', checkboxValues);

ngTagsInput- what is run when selecting one of the options displayed by autocomplete?

I am working on an AngularJS application, and have a dialog which is used to update what is displayed on one of the widgets on a particular page.
The widget is a table, and I want to allow the user to display different data types/ HTML elements in particular cells of the table.
As it currently stands, the cells will display text, a button, or a 'tag' which is a variable taken from the system, and displayed as a particular element using the ngTagsInput library. As the user types into the text input field, the autocomplete feature displays a list of 'tags' that match what has been typed so far- when the user clicks one of these tags in the list, that is when it is then displayed as a tag in the table widget (if they just type the full name of the tag without selecting it from the autocomplete list, it is just displayed as text).
I have made some changes so that when the first character that the user types is a :, the autocomplete list should show a list of the various pages of the application, for which a button linking to that page will be added to the table (i.e. typing page1 would just show the text "page1" in the table cell, but typing :, and selecting 'page1' from the autocomplete list would display a button linking to page1). This functionality currently works as expected,.
I now want to be able to add multiple buttons to a single table cell (assuming that the user inputs the tags into the text field in the dialog in the correct format). The format to do this will be the same as for one button, but with a ; separating each of the individual buttons- for example, to add buttons for page1 & page2 to the same table cell, the user should just type: :page1;page2.
The autocompleteTagsFilter() function, which is what displays the list of available tags/ pages based on what the user has typed so for (i.e. filters the list of available options as the user continues typing) is defined with:
$scope.autocompleteTagsFilter = function(query) {
if (query.startsWith(":")) {
// Split the 'query' search string on ':', to use only the string
var buttonsQuery = query.substring(1);
if (!buttonsQuery && lastTagQryKw) {
buttonsQuery = lastTagQryKw;
}
/*check whether the buttonsQuery variable contains a ';' - if it does, split it */
if(buttonsQuery.includes(';')) {
//console.log("buttonsQuery includes ; - ", buttonsQuery);
var btnsToDisplay = buttonsQuery.split(";");
console.log("btnsToDisplay: ", btnsToDisplay);
}
// Declare variables to be used in 'for' loop
var userPages = pagesPresets;
var page;
var result = [];
// 'For' loop should iterate through the list of user pages,
// and remove path, so that only the page name is shown
for (page in userPages) {
page = userPages[page];
// If the page key starts with 'buttonsQuery', and its length
// is greater than 6 (i.e. just 'pages/' shouldn't be displayed)
// add the page to the list of pages to be displayed.
if (page.key.startsWith(buttonsQuery) && page.key.length > 6) {
result.push(page.key);
//console.log("result- after result.push(page.key): ", result);
} else {
//console.log("userPages: ", userPages);
}
};
for (btn in btnsToDisplay) {
console.log("btn: ", btnsToDisplay[btn]);
result.push(btnsToDisplay[btn]);
console.log("button added to result: ", result);
if (result.length > 0) {
lastTagQryKw = query;
}
// Return the list of pages that match what the user has typed
//console.log("RESULT (when query.startsWith(':') is true) is: ", result);
return result;
// Otherwise, if the user types something that does not start with ':',
//then it should be a tag- search for tags that match this term
} else {
if (!query && lastTagQryKw) {
query = lastTagQryKw;
}
var result = Object.keys(fxTag.getTags()).filter(function(name) {
return name.indexOf(query.toLowerCase()) !== -1;
});
if (result.length > 0) {
lastTagQryKw = query;
}
console.log("RESULT (when query.startsWith(':') is false) is: ", result);
return result;
}
};
As I type, if I start typing with a :, then the browser console displays a list of pages that I could add a button for:
RESULT (when query.startsWith(':') is true) is: (4) ["pages/userpage1", "pages/pagetitle", "pages/userpage2", "pages/auth"]
If I select one of these buttons, that button is correctly added, and when I click the 'Preview' button on the dialog, the dialog closes and the page shows the table with the working button correctly added to the table cell. The console also shows the output:
tag is only one tag: {tag: "pages/auth"}
which comes from the function onAddingTagItem()
However, if I continue typing, rather than selecting one of the buttons shown by the autocomplete, and type out two buttons, i.e.
:pages/userpage1;pages/userpage2
then rather than displaying two buttons, the table cell just displays the text, i.e :pages/userpage1;pages/userpage2.
and I get the console output:
value of tags: (2) [":pages/userpage1", "pages/userpage2"]
The same onAddingTagItem() function is called in both cases, only it runs the if instead of the else when the text entered by the user contains a ;. This function is defined with:
$scope.onAddingTagItem = function(tag) {
if(tag.tag.includes(";")) {
var tags = tag.tag.split(";");
console.log("value of tags: ", tags);
angular.forEach(tags, function(tag, key) {
if(tag.startsWith(":")) {
tag = tag.split(":")[1];
}
angular.extend(tag, toTagItemObj(tag));
})
} else {
console.log("tag is only one tag: ", tag);
}
return true;
};
So, as I understand, it should be returning the tags whether there are one or several of them, because it returns true whether the if or the else is run.
Given that this function always returns true, whether it's the if or the else that has been run, why is it that a button is only displayed when I click an option from the autocomplete list, and not when typing out a button in full?
How can I ensure that the text entered will be displayed as a button when it meets the criteria (starts with a :), even if it's not selected from the autocomplete list, or enable selection of multiple items from the autocomplete list?

Swift array - if a value does not exist

I have a UIPickerView that loads data to an array - it's working, but
then I have the same UIPickerView on another page that I want to display data that is saved when I select an item. This works, if the data exists in the array. If the data dose not exist an index out of range error occurs, and the app crashes.
if data[indexRow].isEmpty
{
distanceLabel.text = ""//works
}else if (){//need this code
print("data")
}else print("data")//need this code
What I need is, how can I test if the value dose not exists (has not been entered on the previous page) in the array without crashing the app.
You could check if the index is greater than or equal to the number of items in your data array.
if(index < data.count){
// When data exists
} else{
// When data does not exist
}

How do I set a class based on a child element's state with Angular?

I am trying to display a results 'table' (built with DIVs as it happens) using Angular. Data looks somethingof it like this:
[['sydney','hotel','2','5','1'],
['sydney','bar','6','5','2'],
['sydney','stand','2','7','3'],
['melbourne','hotel','2','5','1'],
['melbourne','bar','8','0','1']]
What I want firstly is to suppress the repeating city name so that the first row says 'sydney' at the start but the second row and third row don't. Then the fourth says 'melbourne' and the fifth says nothing.
I've achieved this using markup like this:
<div class="row-container"
ng-repeat="row in resultsRows"
<div
ng-repeat="cell in row track by $index"
ng-bind="showValue( cell )">
</div>
</div>
The showValue() function in the controller looks like this:
$scope.currentCityName = '';
function showValue( val ) {
var outValue = '';
if (this.$index === 0) {
if (val === $scope.currentCityName) {
outValue = '';
} else {
$scope.currentCityName = val;
outValue = val;
}
} else {
outValue = val;
}
return outValue;
}
Maybe that's a bit clunky but it works and I get:
sydney hotel 2 5 1
bar 6 5 2
stand 2 7 3
melbourne hotel 2 5 1
bar 8 0 1
Now, though, I want rows that have the city name in them to have a different background colour.
What I think I want is for any 'TR' DIV (I call it that because it contains the left-floated 'TD' DIVs with the data points in them) to check if its first child DIV is not empty (because it has the city name in it) and, if so, to colour its background.
My question is: how do I do that with Angular? Or am I missing another trick..?
How do I get an item in an ng-repeat loop to interrogate a child element?
You are using ng-repeat, which has built-in values like $even and $odd:
$even boolean true if the iterator position $index is even (otherwise false).
$odd boolean true if the iterator position $index is odd (otherwise false).
Use ng-class to give different classed depending on $even and $odd.

how to show only 25 element at one time?

I am trying make table view in ionic using angular js .but I have lot of data to show around 5000 object .So after getting data my UI hang because it is printing the data on dom.So I want to implement lazy loading so that only 100 element is visible to me or only 100 element present in dom only .When user scroll it download another 100 objects or element and removing the uppers element so that my UI not hang .can we do in angular js
I will show you how my UI hang .take a look my example here
my loader hang for around 5 seconds ..
So I tried with infinite scroll in my demo so that I am able to show only 100 element at one time
here is my code of infinite scroll But I am not able to display 100 element at one time I didnot get any error also
<ion-infinite-scroll ng-if="!noMoreItemsAvailable" on-infinite="canWeLoadMoreContent()" distance="10%">
<div class="row" ng-repeat="column in _list | orderBy: sortval:reverse | filter: query">
<div class="col col-center brd collapse-sm" ng-repeat="field in column.columns" ng-show="invoice_column_name['index'].fieldNameOrPath===field.fieldNameOrPath">{{field.value}}</div>
<div class="col col-10 text-center brd collapse-sm"></div>
</div>
</ion-infinite-scroll>
</ion-content>
Updated Plunker
I took a little different approach then the others.
There is a variable at the top of the controller called showitems. This controls how many items you want to show at a time. The counter variable will keep track of where how many items are shown. Initially, the value is set to the showitems value since we're going to prepopulate the dataset with the first items immediately in the ShowViewAfterSuccess function.
var showitems = 100;
var counter = showitems;
In your ShowViewAfterSuccess function, I added the data to a scope variable called $scope.total_invoice_records.
Next, I run the first array slice on the data. This will pass the first x number of records to the $scope.invoice_records based on the value set in the showitems variable. This initializes the view with the first set of records.
$scope.total_invoice_records=data.records;
$scope.invoice_records = $scope.total_invoice_records.slice(0, showitems);
I added a loadMore function that simply grabs the next x number of records from the total record set and concatenates them to the current set in $scope.invoice_records and increments the counter. loadMore will also check if there are still more records to load and broadcasts the message to the ionic infinite scroll directive to remove the spinner.
$scope.noMoreItemsAvailable = false;
$scope.loadMore = function() {
var next = $scope.total_invoice_records.slice(counter, counter+showitems);
$scope.invoice_records = $scope.invoice_records.concat(next);
counter = counter+showitems;
if (counter>=$scope.total_invoice_records.length) {
$scope.noMoreItemsAvailable = true;
}
$scope.$broadcast('scroll.infiniteScrollComplete');
};
Most importantly, remember to set the immediate-check attribute on the infinite scroll element to false:
<ion-infinite-scroll immediate-check="false" ng-if="!noMoreItemsAvailable" on-infinite="loadMore()" distance="10%"></ion-infinite-scroll>
You need to set up a pagination rather than use infinite scroll; or keep the functionnality of infinite scroll as is.
but if you wish to still use infinite scroll, then when you load your next datas into _list, just before filling in the new elements, clean your _list with a _list.length= 0
But you will have sideeffects that I don't know such as :
- how to load the 100 first elements ?
- the page will jump from full with 100 elements, cleaned to 0, and filled with next 100. This will lead, I assume, to an unpleasant effect
My configuration of ion-infinite is the following :
<ion-infinite-scroll
ng-if="!myModel.maxItemLoaded"
icon="ion-loading-c"
on-infinite="loadMoreData()"
distance="10"
>
Which means :
- when user scroll gets on the 10 last % of the page height, loads loadMoreData
If user never scoll, then he has only the first data shown.
Edit:
Here is an updated plunkr
http://plnkr.co/edit/B5KCbc8hr66upCXMvXSR?p=preview
Few remarks :
- the infinite scroll directive is independent and shall not surroung your table
- accessing to to index is done by $index, not with 'index'
- the load functionnality has been modified to load the next 100 elements
$scope.populateList = function() {
var size = $scope._list.length;
var maxSize = size + 100;
if (maxSize > $scope.invoice_records.length)
maxSize = $scope.invoice_records;
console.log("populateList",size,maxSize,$scope.invoice_records)
for (var i = size; i <= maxSize; i++) {
console.log("push",$scope.invoice_records[i])
$scope._list.push($scope.invoice_records[i]);
}
console.log($scope._list.length);
$scope.$broadcast('scroll.infiniteScrollComplete');
}
Angular should work with 5000 object, if it is read only , you can use one time binding
An expression that starts with :: is considered a one-time expression.
One-time expressions will stop recalculating once they are stable,
which happens after the first digest if the expression result is a
non-undefined value (see value stabilization algorithm below).
<span ng-bind="::name"></span>
I don't know infinite scrolling, but if I had to implement something like that i would have used ng-filter 'limit'.
ng-repeat="column in _list | limit : limitValue"
And then bind any button/scroll event to
$scope.limitValue = $scope.limitValue + "10";
Ideally you should not have brought this much data in 1 call. Now, if you have, you can achieve this by a small tweak.
Break your data in chunk of 100. And set that 100 in $scope.
var brokenData = [];
var totalData = x; // Total 5000 records
var pages = parseInt(totalData.length/100);
if(totalData.length % 100 !== 0) {
pages += 1;
}
for (var i = 0; i < pages; i++){
if(i == pages - 1) {
brokenData.push(totalData);
} else {
brokenData.push(totalData.splice(0,100));
}
}
Now set
$scope.pages = pages;
And for 1st page or for 1st time,
$scope.pageData = brokenData[0];
$scope.currentPage = 0 + 1;
This will show only 100 records on your page and sets current page as 1.
Now you can choose any pagination tool or bind window scroll events and just update the above 2 things
Like for 2nd page
$scope.pageData = brokenData[1];
$scope.currentPage = 1 + 1;

Resources