Coding custom Screen Navigation into Lightswitch HTML - javascript

I would like to have Button action event in LS HTML go slightly against the built-in navigation framework.
Specifically, to have LS navigate from one AddEditScreen to another AddEditScreen automatically, triggered by this Button event.
The trick is this - I need it to navigate to the AddEditScreen of the "next item up" in the Browse Screen List, without returning to the Browse Screen.
Example:
Select item 'ABC01' on a Browse Screen > Navigate to the AddEditScreen for 'ABC01' > edit 'ABC01' > when finished editing, trigger an event that will enable LS to navigate directly to the AddEditScreen for 'ABC02' from the Browse Screen list.
I have an open mind about what that event could be. A Button...anything at all.
I have created a Button and chose 'Write my own method'.
Does this look even close to code that will work, or will LS need to get the value of 'ABC01' from a query of some type?
myapp.AddEditHoldingInventory.Method_execute = function (screen) {
// Write code here.
var navigateToNextScreen = function (Method) {
return screen.getStrRqsNum().then(function (StrRqsNum) {
if (!!StrRqsNum) {
return myapp.applyChanges().then(function () {
var paramValue = (Number(StrRqsNum) += 1).toString();
return myapp.ShowAddEditHoldingInventory(id);
}
});
});
}
The code above is modified by me, and I am not a programmer or developer. It is snippets from pieces I have gathered and am trying to make sense of.
What the code is trying 'miserably' to achieve, is:
get the value of StrRqsNumber > save the edits made on the screen > add +1 to the value of StrRqsNumber > navigate to the AddEditSCreen of the record with the new value.
StrRqsNumber = a column with a value. It is unique and identifies an asset. This is most likely NOT the best way to achieve what I am trying to achieve, so I am here for advice. I don't have to use this as the parameter, as long as I can hit the 'next item up' from the list.
Thank you very much for any input. I will be SO stoked to get this behavior working.

This problem was solved by joshbooker. Here was the solution, which only needed minimal project specific tailoring...
"Question
Vote as helpful
0
Vote
What I want to achieve is this, for example:
Browse Screen > Select item 1 of 15 in the list > scan in the information we need on the AddEditScreen for item 1 > hit the 'trigger', and have LS automatically Save that edit, then navigate to the AddEditScreen of item 2 of 15 > and so on.
Here is a working solution for this:
/// <reference path="~/GeneratedArtifacts/viewModel.js" />
myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute = function (screen)
{///custom screen method to set selected item to next StrRqsNum
//calc next num
var nextNum = (Number(screen.HoldingInventories.selectedItem.StrRqsNum) + 1).toString();
// iterate collection data to find the next item
var nextItem = msls.iterate(screen.HoldingInventories.data)
.where(function (i)
{
return i.StrRqsNum == nextNum;
}).first();
if (nextItem)
{ //if found - select the item & return true
screen.HoldingInventories.selectedItem = nextItem;
return true;
}
else
{ //not found - return false
return false;
};
};
myapp.BrowseHoldingInventories.TapMethod_execute = function (screen) {
// tap method of list item on browse screen.
//handy way to save/set scroll position
var scrollTopPosition = $(window).scrollTop();
//currently selected item
var item = screen.HoldingInventories.selectedItem;
//showAddEditScreen - pass item
// beforeShown: setup binding on FieldB
//afterClosed: if commit & select next then recurse
myapp.showAddEditHoldingInventory(item, {
beforeShown: function (addEditScreen)
{//this executes before the screen is shown
//find the trigger field
var contentItem = addEditScreen.findContentItem("FieldB");
if (contentItem)
{ //databind to catch value change
contentItem.dataBind(contentItem.bindingPath, function(newValue){
if (newValue && contentItem.oldValue && newValue != contentItem.oldValue)
{ //if change then commit - this triggers close of addEditScreen
myapp.commitChanges();
}
contentItem.oldValue = newValue;
});
}
},
afterClosed: function (addEditScreen, navigationAction)
{//this executes after the screen is closed
//scroll browse screen to where we left off
$(window).scrollTop(scrollTopPosition);
//if commit
if (navigationAction == msls.NavigateBackAction.commit)
{ //try to select next item in list
if (myapp.BrowseHoldingInventories.selectNextStrRqsNum_execute(screen) == true)
{ //next item selected then recurse
myapp.BrowseHoldingInventories.TapMethod_execute(screen);
}
}
}
});
};
"

Related

Slick Carousel - The "slickRemove" method is unable to remove the "slick-cloned" slide/item based on the "click" event or "data-slick-index" attribute

short description of the bug / issue, provide more detail below.
I am building a drag-and-drop quiz app. If a user drags a cloned item ( slick generates cloned items in infinite loop option by default) and drops it at the correct dropzone, I want to remove the dropped item from the carousel based on "data-slick-index" attribute value of the dropped item.
But the "slickRemove" method of Slick Carousel is unable to remove the "slick-cloned" slide + its original slide based on the "click" event on the cloned item or "data-slick-index" attribute value of the cloned item.
====================================================================
[ paste your jsfiddle link here ]
http://jsfiddle.net/anisur5/ehpacfvj/30/
====================================================================
Steps to reproduce the problem
Go to this link: http://jsfiddle.net/anisur5/ehpacfvj/30/
Click on the second dot (•) and Inspect "slide10" which contains
data-slick-index="-1". If you click on it (slide10), Slick js is
unable to delete the clicked item.
It happens whenever I click on
the "slick-cloned" slides.
====================================================================
What is the expected behaviour?
I want slick to remove the clicked item even though it is a "slick-cloned" item.
====================================================================
What is observed behaviour?
Slick's "slickRemove" method can not delete the clicked item if the item is "slick-cloned".
====================================================================
More Details
Which browsers/versions does it happen on? => All
Which jQuery/Slick version are you using? => Latest
Did this work before? => No
Here is the code that slick.js uses to remove slides. I added a comment tag for return false; so that Slick can remove items that come with negetive value in "data-slick-index" attribute( I also tried to remove items based on "data-slick-index" ).
Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
var _ = this;
if (typeof(index) === 'boolean') {
removeBefore = index;
index = removeBefore === true ? 0 : _.slideCount - 1;
} else {
index = removeBefore === true ? --index : index;
}
if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
// return false;
}
_.unload();
if (removeAll === true) {
_.$slideTrack.children().remove();
} else {
_.$slideTrack.children(this.options.slide).eq(index).remove();
}
_.$slides = _.$slideTrack.children(this.options.slide);
_.$slideTrack.children(this.options.slide).detach();
_.$slideTrack.append(_.$slides);
_.$slidesCache = _.$slides;
_.reinit();
};
If you add the count of original slides to the negative data-slick-index of the clones, it should give you the index of the original. Only slick does not appear to update that value correctly - so by using that alone, I ended up removing slides with a higher index than the clicked one, when clicking on an original.
Only workaround I could find on the quick, is to store the reference to the slide, on the slide, before the slider gets initialized - then the clones will still refer to the original. Via that reference, you can then find the index of the original in the list of original slides (exclude the clones), and then use that value to remove the slide.
// before slider initialization:
$('.slider div').each(function(i,e) {
$(e).data('self', e);
});
// slider init here
// ...
//Remove slick item based on click.
$(".slider").on("click", ".slick-slide", function() {
var originalSlide = $(this).data('self')
index = $('.slider .slick-slide:not(.slick-cloned)').index(originalSlide);
$(".slider").slick('slickRemove', index);
});
http://jsfiddle.net/1hx5s39z/2/

Link two elements, store them, and send them to remove function - Pure Javascript

I have a little Pure Javascript prototype demonstrating shopping cart functionality.
I have a Button which adds the item to the cart (and toggles to an ON state) and then a Card which represents the item in the shopping cart.
So far I have worked;
Attach data to Add to Cart Button ✓
Send data from Button to Shopping Cart and create new Item Card ✓
However, I cannot work out how to link Button and newly created Item Card so I can:
Remove Item Card and toggle button OFF or
Toggle button OFF and remove the correct Item Card
https://codepen.io/rhysyg03/pen/PdyyWE
Your help would be much appreciated.
FYI - this is just for a demo so it doesn't need to be production ready code.
Thank you.
const shoppingCartEl = document.querySelector('#js-shopping-cart');
const addToCartButton = document.querySelector('#js-add-to-cart');
var buttonToggle = false;
var itemOneData = {
name:'Shoes',
price:"$105.00"
}
function addItem(button, itemData) {
console.log("ADD");
// var itemEl = createElement('<div class="item-card"></div>');
const itemEl = document.createElement("div");
itemEl.classList.add("item-card");
itemEl.innerHTML = itemData.name + itemData.price + "<button id='js-item-cart-remove'>Remove</button>";
shoppingCartEl.appendChild(itemEl);
const itemCardRemove = document.querySelector('#js-item-cart-remove');
itemCardRemove.addEventListener('click', () => {
removeItem();
})
}
function removeItem() {
console.log("REMOVE");
// how to do this part
}
addToCartButton.addEventListener('click', () => {
if (buttonToggle == false) {
addItem(addToCartButton, itemOneData);
buttonToggle = true;
addToCartButton.innerHTML = "Remove from Cart";
} else {
// How to do this part
removeItem();
buttonToggle = false;
addToCartButton.innerHTML = "Add to Cart";
}
})
(I am sorry I am tired a bit, you should read the very ending, firstly)
You should have items like this:
var itemOneData = {
id: 1,
name:'Shoes',
price:"$105.00"
}
var itemTwoData = {
id: 2,
name:'Shoes',
price:"$105.00"
}
Then you should store identifier on the item card element:
...
itemEl.classList.add("item-card");
itemEl.setAttribute("data-item-id", itemData.id)
...
After this, when clicking on remove button, you should:
Get the id of item to be removed itemEl.getAttribute("data-item-id")
Pass the id to remove function removeItem(id)
(this was where I've given up) Find the item with the attribute "data-item-id" having value of the id and replace it to empty string ""
There is another solution, probably far less complex: when clicking on remove button simply find it's parent and replace it with empty string.
This is a quick solution, just to get what you are looking for, but of course, maybe you should be having some 'state' where you have your cart items, and render the UI based on that state. In this quick solution, what I am doing is event delegation, as we know that the one element that will exist at the beginning is the cart div. So we place the event on this element and then check which element are we clicking, and also doing some check so we assure only that an item-card can be deleted. codepen.io/anon/pen/WgaYxe?editors=1011
Hope this helps and if you need more details please feel free to ask!
Bye

Applying .click event only to links in a certain div-container

The code already creates a navigation based on a JSON-file. The url are accessible by writing data.chapter[].subchapter[].url, the according title through data.chapter[].subchapter[].title
In case you are interested in that part or want the complete code, I uploaded it there: http://fabitosh.bplaced.net/SkriptET_iFrame_v2/
The goal now is to create a right sidebar which shows the links to the next and previous files in the structure. My approach is below.
What confuses me, is that back() is called until subchap is zero, when a link in #left is being clicked on. It should only be called when the previous-link is being clicked on. What do I have to change in order to achieve that?
Thanks a lot already!
var chap; //position in the array of the currently open chapter
var subchap; //position in the array of the currently open subchapter
function update_right() {
var path = data.chapter[chap].subchapter;
//Previous Page
if(subchap > 0) {
$("#prev").html("<b>Previous:</b><a href='"+path[subchap-1].url+"'>"+path[subchap-1].title+"</a><br/>");
$("#prev > a").click(back());
} else { //subchap == 0
$("#prev").html("");
};
}
function back() {
subchap--;
update_right();
}
$(document).ready(function() // DOM needs to exist in order to be able to add stuff in there
{
...Navigation being built up...
//------ onClick Navigation
$('#left > ul > li > a').click(
function(e)
{
chap = $(this).attr("data-chap");
subchap = $(this).attr("data-subchap");
update_right();
}
);
});

SlickGrid Header menu - multiple selection for a single column

I have been using SLickGrid in my grails application but for now i am only able to tag a column just with one option from the menu drop down.
the js code for this is :-
var headerMenuPlugin = new Slick.Plugins.HeaderMenu({buttonImage:window.params.dropDownIconUrl});
headerMenuPlugin.onBeforeMenuShow.subscribe(function(e, args) {
var menu = args.menu;
var i = menu.items.length;
var iconClass = undefined
menu.items[0].iconCssClass = (args.column.name === $("#sciNameColumn").val())?'icon-check':undefined
menu.items[1].iconCssClass = (args.column.name === $("#commonNameColumn").val())?'icon-check':undefined
});
headerMenuPlugin.onCommand.subscribe(function(e, args) {
var name = args.column.name;
if(args.command === 'sciNameColumn') {
if(args.column.name == $('#sciNameColumn').val())
name = ''
if(args.column.name == $('#commonNameColumn').val())
$('#commonNameColumn').val('');
$('#sciNameColumn').val(name);
} else if(args.command === 'commonNameColumn') {
if(args.column.name == $('#commonNameColumn').val())
name = ''
if(args.column.name == $('#sciNameColumn').val())
$('#sciNameColumn').val('');
$('#commonNameColumn').val(name);
}
selectNameColumn($('#commonNameColumn'), commonNameFormatter);
selectNameColumn($('#sciNameColumn'), sciNameFormatter);
});
grid.registerPlugin(headerMenuPlugin);
But now the requirement is that i need more than one selection for a column from the drop down and save the selections and use it later on and also same selections can be done for multiple columns.
Hope i am clear enough, Thanks for any support
What I did is change the headerMenu plugin to introduce two features:
a new item option, keepOpen, which prevents the menu to close after a command, and
refreshing the item details (specifically iconImage and iconCssClass) after a command (only if the menu was kept open).
I'll try to set up the pull request on the SlickGrid repo if I find the time.

Jquery Chosen plugin. Select multiple of the same option

I'm using the chosen plugin to build multiple select input fields. See an example here: http://harvesthq.github.io/chosen/#multiple-select
The default behavior disables an option if it has already been selected. In the example above, if you were to select "Afghanistan", it would be greyed out in the drop-down menu, thus disallowing you from selecting it a second time.
I need to be able to select the same option more than once. Is there any setting in the plugin or manual override I can add that will allow for this?
I created a version of chosen that allows you to select the same item multiple times, and even sends those multiple entries to the server as POST variables. Here's how you can do it (fairly easily, I think):
(Tip: Use a search function in chosen.jquery.js to find these lines)
Change:
this.is_multiple = this.form_field.multiple;
To:
this.is_multiple = this.form_field.multiple;
this.allows_duplicates = this.options.allow_duplicates;
Change:
classes.push("result-selected");
To:
if (this.allows_duplicates) {
classes.push("active-result");
} else {
classes.push("result-selected");
}
Change:
this.form_field.options[item.options_index].selected = true;
To:
if (this.allows_duplicates && this.form_field.options[item.options_index].selected == true) {
$('<input>').attr({type:'hidden',name:this.form_field.name,value:this.form_field.options[item.options_index].value}).appendTo($(this.form_field).parent());
} else {
this.form_field.options[item.options_index].selected = true;
}
Then, when calling chosen(), make sure to include the allows_duplicates option:
$("mySelect").chosen({allow_duplicates: true})
For a workaround, use the below code on each selection (in select event) or while popup opened:
$(".chosen-results .result-selected").addClass("active-result").removeClass("result-selected");
The above code removes the result-selected class and added the active-result class on the li items. So each selected item is considered as the active result, now you can select that item again.
#adam's Answer is working very well but doesn't cover the situation that someone wants to delete some options.
So to have this functionality, alongside with Adam's tweaks you need to add this code too at:
Chosen.prototype.result_deselect = function (pos) {
var result_data;
result_data = this.results_data[pos];
// If config duplicates is enabled
if (this.allows_duplicates) {
//find fields name
var $nameField = $(this.form_field).attr('name');
// search for hidden input with same name and value of the one we are trying to delete
var $duplicateVals = $('input[type="hidden"][name="' + $nameField + '"][value="' + this.form_field.options[result_data.options_index].value + '"]');
//if we find one. we delete it and stop the rest of the function
if ($duplicateVals.length > 0) {
$duplicateVals[0].remove();
return true;
}
}
....

Categories

Resources