2sxc | SQL Datasource - LINQ Filter Query - linq

I have a SQL Datasource setup to get all documents of a certain extension from the standard DNN 'Files' table but I want to add an extra level of specification on what category of file to display but not sure how best to go about it. See my current SQL Datasource code below:
#using ToSic.Eav.DataSources
#functions
{
// Default data initialization - should be the place to write data-retrieval code
// In the future when routing & pipelines are fully implemented, this will usually be an external configuration-only system
// For now, it's done in a normal event, which is automatically called by the razor host in 2SexyContent
public override void CustomizeData()
{
var source = CreateSource<SqlDataSource>();
// source.TitleField = "EntityTitle"; // not necessary, default
// source.EntityIdField = "EntityId"; // not necessary, default
// source.ConnectionString = "..."; // not necessary, we're using the ConnectionStringName on the next line
source.ConnectionStringName = Content.ConnectionName;
// Special note: I'm not selecting * from the DB, because I'm activating JSON and want to be sure that no secret data goes out
source.SelectCommand = "Select Top 10 FileId as EntityId, FileName as EntityTitle, PublishedVersion, UniqueId, FileName, Size as Size, Extension as Extension, CreatedOnDate as Date, Folder as Folder FROM Files WHERE PortalId = #PortalId AND Extension = 'docx' OR Extension = 'xlsx' OR Extension = 'pdf'";
source.Configuration.Add("#PortalId", Dnn.Portal.PortalId.ToString());
Data.In.Add("FileList", source.Out["Default"]);
// enable publishing
Data.Publish.Enabled = true;
Data.Publish.Streams = "Default,FileList";
}
}
I want to sync the 2sxc Categories entity with DNN's Tab/Page Taxonomy Tags/Categories so as to allow a user to select a DNN Tag on Page setup which (if synced with the 2sxc Categories entity) will allow me to assign a specific doc/excel/pdf file (already connected via 2sxc iCache to a 2sxc Category) to an app based on the SQL Datasource which connects via joining the taxonomy_terms table with the content items table and in turn with the content item tags table which connects with the DNN tabs table.
How can I correct my LINQ/Razor code below to filter my Categories to only display files with the exact 'Services' Category assigned to them. I will use this filter to sync with the Taxonomy Tag 'Services' (exact match) which I want to link to the 2sxc Category (which has an uploaded Adam file already connected via 2sxc iCache) with DNN Taxonomy term 'Services'?
#foreach (var file in AsDynamic(Data.In["FileList"]).Where(i =>
(i.Category as List<dynamic>).Any(c => c.EntityId == FileList.EntityId)))
{
<li>#file.FileName</li>
}
I have looked in detail at the wiki notes on https://github.com/2sic/2sxc/wiki/DotNet-Query-Linq and I am stuck on getting the correct syntax for the category filter with using a foreach with the SQL Datasource template.
Cheers...

I believe we have solved this by mail already.
One minor recommendation: if you use DnnSqlDataSource instead of the SqlDataSource you already have the correct connection string for your current DNN. See also http://2sxc.org/en/docs/Feature/feature/4670 as well as https://github.com/2sic/2sxc/wiki/DotNet-DataSources-All

Yes, the filter I needed was as you provided below:
#using ToSic.SexyContent
#{
// all QandA items
var all = AsDynamic(App.Data["QandA"].List);
// the filter value, can be set in template
// but usually you would either get it from url with Request["urlparam"]
// or from a setting in the view, using Content.Category
var currentCat = "Business";
// filter, find any which have the current category
var filtered = all
.Where(p => (p.Categories as List<DynamicEntity>).Any(c => AsDynamic(c).Name == currentCat));
}
<div class="clearfix">
#foreach (var q in filtered)
{
<div class="sc-element" data-tags="#String.Join(",", ((List<DynamicEntity>)q.Categories).Select(a => AsDynamic(a).EntityId))">
#Edit.Toolbar(Content)
<div class="col-md-12">
<div class="">
<a href="#q.Link" class="">
<span class="">#q.Link</span>
</a>
<p>#q.Title</p>
</div>
</div>
</div>
}
</div>
Thanks again!

Related

Laravel 8 & Yajra Datatables complicated search

I have a datatable that fetches orders and is working and displaying properly. I show the orders to the users that initiated them. Then they can only search on their owns orders. Now I need to display a message to a user, if an order was found but it was initiated by another user, instead of displaying an empty result in the datatable. This will happen after typing in the search box and not when loading the datatable in the beggining. The problem is that the query already filters the results by user id so I cannot change it during manual search.
I can display code if needed but the function is quite big and I don't really need code but the logic/way of doing that.
Do you have any suggestions on how I could accomplish this?
Well, maybe not the best way to do it but that's how I solved it:
In the controller, I check for the search field, and run a query on the relationship but only on the orders that have different seller than the logged in user:
$otherSeller = "";
if(!empty($request->search['value']))
{
$ordersOtherSeller = Order::where('status_id', "!=", 3)->where('seller_id', '!=', $loggedUser->id)->whereHas('user', function ($q) use ($request){
$q->searchFullName($request->search['value']);
})->first();
if($ordersOtherSeller != NULL && $ordersOtherSeller->count() > 0)
$otherSeller = $ordersOtherSeller->user->full_name . ' ' . $ordersOtherSeller->seller->full_name;
}
And I set a custom variable with the table's json:
...
->with('otherSeller', $otherSeller)
->make(true);
Then on the datatable jquery drawCallBack, I check for a populated string that guarantees that the result is not returned by a query from the current user:
fnDrawCallback: function( oSettings ) {
var api = this.api();
if(api.ajax.json().otherSeller != "")
{
$('#alert-info span').text(api.ajax.json().otherSeller);
$('#alert-info').show();
}
else
$('#alert-info').hide();
},
And last is the toggling of the materialert element with updated text:
<div id="alert-info" class="materialert info" style="display: none;">
<i class="material-icons">info</i> <span></span>
<button type="button" class="close-alert">×</button>
</div>

How to display only a drop-down list of items not previously selected

I have two tables
tenant=>id,name,email,property_id
property=>id,propertyname,location
The ‘tenant’ and ‘property’ table has a one to relation.
My tenant/create.blade.php has a drop-down list of all the properties in the database available for rent.
For example if in the database the following properties are inserted A,B,C,D,E,F. The drop-down list displays all properties including those already taken. As in figure
I want it to display only properties not taken. For example if out of all properties available A,B,C has previously been assigned the it should only display a drop-down list of D,E,F
I think I can do this in the controller but dont know how.
Here is my TenantsController create function
public function create()
{
$property = Property::pluck('propertyname','id');
return view('tenants.create',compact('property'));
}
The create.blade.php has the following code to display the drop-down list
<div class="form-group">
{{Form::label('property name','Property Name')}}
{{Form::text('propertyname','',['class'=>'form-control','placeholder'=>'Property Name'])}}
</div>
There could be more solutions, but right now I can think of $collection->diff() to quickly solve it within your laravel app.
$properties = Property::all(); // write query to fit your needs
$taken = Property::taken(); // write query to retrieve the unavailable properties
$diff = $properties->diff($taken);
$options = $diff->pluck('name', 'id')->toArray();
Now, pass the $options to your blade view & loop through it to generate <option>.

Kendo ui list view losing focus when changing data

I have a kendo ui listview with a template the conditionally hides elements based on the underlying data. An example would be as follows:
<script type="text/x-kendo-template" id="template">
<div class="product">
<img src="../content/web/foods/#= ProductID #.jpg" alt="#: ProductName # image" />
<h3>#:ProductName#</h3>
<p>#:kendo.toString(UnitPrice, "c")#</p>
<div>
# if (Discontinued) { #
Discontinued Product
# } #
</div>
</div>
</script>
If i modify the underlying dataSource items to set Discontinued with the following code:
data[index].set('Discontinued', true);
If the index is the currently selected item then that item looses focus and is no longer selected.
Please see the following dojo example http://dojo.telerik.com/UlOze, select an item from the list and then set it to discontinued.
Has anybody found a solution / workaround for this issue ?
Thanks.
------------- FINAL SOLUTION --------------
Following on from dimodi's answer below I pieced together the solution.. For this to work the dataSource must have the schema -> model -> id property set.
1st capture the currently selected data item:
var selectedItem = $(listElement).find(".k-state-selected");
var selectedDataItem = list.dataItem(selectedItem);
2nd: After calling .set re-find the data item and set the k-state-selected class. This is nessesary as the list component is regenerating the uid's.
if (selectedDataItem) {
var newSelectedItem = list.dataSource.get(selectedDataItem.ProductID)
var uid = newSelectedItem.uid;
jQuery("[data-uid='" + uid + "']").addClass("k-state-selected");
}
I've updated the original dojo to show this solution, incase it helps someone else.
When a data item is changed, its corresponding ListView item is re-rendered to apply the changes. As a result, the selection is lost, as it is a purely visual feature that is not persisted across rebinds. You can check if an item is selected before using set() and then restore the selection manually by applying a k-state-selected class to the element afterwards.

My Recent Orders on home page, outside of user dashboard

I need to know if I need to create a widget for something like this, or just add a recent orders block to the home page layout.xml.
it should only reflect order for that store.
I know that the user has to be logged in for this to work, but there could be some cookie magic applied to detect the user, and display a short list of recent orders, without displaying the items, which I think is not a massive privacy / security issue.
This is for use in a mobile app, where space is limited, and quick links are helpful...
There will then simply be a link to reorder / view as in the dashboard, and that view would require a descent login.
What is the best way to go about it, if at all possible.
this is a Paypal app, and the recent orders are seen via:
http://www.sitename.com/storename/jsonsales/order/recenttemplate?s=2752732063744
Thanks in Advance.
On top of my head, what I would do is create a custom module with observer to catch when order placed, trigger the process of storing the order in the cookie (e.g. last 3 orders?)
Then just create a block in that module to read the data from the cookie.
After that render that block into the template (either via editing appropriate .phtml or create your own .phtml and add it inside layout.xml).
Hope this helps.
For those that might want to try this, with a module called Paypal order Ahead.
Because this is a paypal specific web app, I was able to do this using the javascript functions calling the json templates.
On the /app/design/frontend/paypal/test/template/cms/index.phtml I added the following:
<div class="content-box greybg recentordercontainer">
<div id="productError_<?php echo $sid; ?>" style="display:none"></div>
<div class="page-title text-title"><?php echo $this->__('My Recent Orders'); ?></div>
<div id="recentorder-list-box_<?php echo $sid; ?>" class=""></div>
<div class="cart-empty" id="cart-empty_<?php echo $sid; ?>" style="display:none">
<div class="box-shadow">
<div class="error-desc cart-row2" style="margin-top:10px;"><?php echo $this->__('You have not yet made any purchases.'); ?></div>
</div>
<div class="pay-now" id="contshop_<?php echo $sid; ?>">
<?php echo Mage::getStoreConfig('checkout/options/continue_shopping_text'); ?>
</div>
</div>
</div>
Then I added some javascript in the script section at the bottom of this template:
getRecentOrderBlockJSON("<?php echo $sid; ?>")
function getRecentOrderBlockJSON(id) {
$.getJSON(storeRootUrl+"/jsonsales/order/recent", function(jsonObj) {
renderRecentOrderBlock(jsonObj,id);
});
}
function renderRecentOrderBlock(jsonObj,id) {
var dataObj = jsonObj.recentorder;
// Recent Order Item box target
var ulObj = $("#recentorder-list-box_"+id);
// Display error message on top
if (jsonObj.messages.error.length >0) {
var pdObj = $("#productError_"+id);
var tplHTML = $("#ErrorPageTemplate").html();
for (key in jsonObj.messages) {
var re = new RegExp("%"+key+"%", "g");
tplHTML = tplHTML.replace(re,jsonObj.messages[key]);
}
pdObj.append(tplHTML);
$("#productError_"+id).css("display","block");
}
// have recent order
if ( dataObj && dataObj.length > 0 ) {
for ( var i=0; i<dataObj.length; i++ ) {
var tplHTML = $("#RecentOrderFrontTemplate").html();
// date
var re = new RegExp("%created_at%", "g");
//tplHTML = tplHTML.replace(re,dataObj[i].order.created_at);
tplHTML = tplHTML.replace(re,dataObj[i].order.created_at_localetime);
// update id
var re3 = new RegExp("%id%", "g");
tplHTML = tplHTML.replace(re3,dataObj[i].order.id);
// update rid
var re4 = new RegExp("%rid%", "g");
tplHTML = tplHTML.replace(re4,id);
ulObj.append(tplHTML);
// Recent Ordered Item box
var orderObj = $("#order-list-attr-"+id+dataObj[i].order.id);
} // for
}
}
And that gave me the list, provided that there was a cookie called ppmeccookie, with the value of your customerid. This cookie normally gets generated when you have done a paypal checkout before, using this paypal App.
Thanks for the help.

How to update a label from a postback in MVC3/Razor

MVC/Razor/Javascript newbie question:
I have a MVC3/Razor form where the use can select a single product from a drop down list.
<div class="editor-label">
Product
</div>
<div class="editor-field">
#Html.DropDownList("ProductID", (IEnumerable<SelectListItem>)ViewBag.Products, "--Select One--")
#Html.ValidationMessageFor(model => model.ProductID)
</div>
What I then want is to display the price of the selected product on a label just below the drop down list (model property name is Amount).
This should be pretty easy, but I am pretty new at Razor, and know almost nothing about Javascript, so I would appreciate any verbose explanations of how do do it, and how it all hangs together.
Add a div/span under the Dropdown .
#Html.DropDownList("ProductID", (IEnumerable<SelectListItem>)ViewBag.Products, "--Select One--")
<div id="itemPrice"></div>
and in your Script, make an ajax call to one of your controller action where you return the price.
$(function(){
$("#ProductId").change(function(){
var val=$(this).val();
$("#itemPrice").load("#Url.Action("GetPrice","Product")", { itemId : val });
});
});
and have a controller action like this in your Product controller
public string GetPrice(int itemId)
{
decimal itemPrice=0.0M;
//using the Id, get the price of the product from your data layer and set that to itemPrice variable.
return itemPrice.ToString();
}
That is it ! Make sure you have jQuery loaded in your page and this will work fine.
EDIT : Include this line in your page to load jQuery library ( If it is not already loaded),
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
The Amount isn't available to your view when the user selects a product (remember the page is rendered on the server, but actually executes on the client; your model isn't available in the page on the client-side). So you would either have to render in a JavaScript array that contains a lookup of the amount based on the product which gets passed down to the client (so it's available via client-side JavaScript), or you would have to make a callback to the server to retrieve this information.
I would use jQuery to do this.
Here's a simple example of what the jQuery/Javascript code might look like if you used an array.
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
$(document).ready(function() {
// This code can easily be built up server side as a string, then
// embedded here using #Html.Raw(Model.NameOfPropertyWithString)
var list = new Array();
list[0] = "";
list[1] = "$1.00";
list[2] = "$1.25";
$("#ProductID").change(displayAmount).keypress(displayAmount);
function displayAmount() {
var amount = list[($(this).prop('selectedIndex'))];
$("#amount").html(amount);
}
});
</script>
<select id="ProductID" name="ProductID">
<option value="" selected>-- Select --</option>
<option value="1">First</option>
<option value="2">Second</option>
</select>
<div id="amount"></div>
You'll want to spend some time looking at the docs for jQuery. You'll end up using it quite a bit. The code basically "selects" the dropdown and attaches handlers to the change and keypress events. When they fire, it calls the displayAmount function. displayAmount() retrieves the selected index, then grabs the value out of the list. Finally it sets the HTML to the amount retrieved.
Instead of the local array, you could call your controller. You would create an action (method) on your controller that returned the value as a JsonResult. You would do a callback using jquery.ajax(). Do some searching here and the jQuery site, I'm sure you'll find a ton of examples on how to do this.

Resources